Add support for built-in contracts

This commit is contained in:
Michael Vines
2018-09-18 12:46:59 -07:00
parent 7dad281f69
commit a96ab72e8e
6 changed files with 445 additions and 35 deletions

View File

@@ -6,15 +6,6 @@ import bs58 from 'bs58';
import type {Account, PublicKey} from './account';
/**
* @private
*/
function bs58DecodePublicKey(key: PublicKey): Buffer {
const keyBytes = Buffer.from(bs58.decode(key));
assert(keyBytes.length === 32);
return keyBytes;
}
/**
* @typedef {string} TransactionSignature
*/
@@ -25,6 +16,17 @@ export type TransactionSignature = string;
*/
export type TransactionId = string;
/**
* List of Transaction object fields that may be initialized at construction
*/
type TransactionCtorFields = {|
signature?: Buffer;
keys?: Array<PublicKey>;
contractId?: PublicKey;
fee?: number;
userdata?: Buffer;
|};
/**
* Mirrors the Transaction struct in src/transaction.rs
*/
@@ -41,6 +43,11 @@ export class Transaction {
*/
keys: Array<PublicKey> = [];
/**
* Contract Id to execute
*/
contractId: ?PublicKey;
/**
* A recent transaction id. Must be populated by the caller
*/
@@ -56,6 +63,10 @@ export class Transaction {
*/
userdata: Buffer = Buffer.alloc(0);
constructor(opts?: TransactionCtorFields) {
opts && Object.assign(this, opts);
}
/**
* @private
*/
@@ -74,11 +85,18 @@ export class Transaction {
transactionData.writeUInt32LE(this.keys.length, pos); // u64
pos += 8;
for (let key of this.keys) {
const keyBytes = bs58DecodePublicKey(key);
const keyBytes = Transaction.serializePublicKey(key);
keyBytes.copy(transactionData, pos);
pos += 32;
}
// serialize `this.contractId`
if (this.contractId) {
const keyBytes = Transaction.serializePublicKey(this.contractId);
keyBytes.copy(transactionData, pos);
}
pos += 32;
// serialize `this.lastId`
{
const lastIdBytes = Buffer.from(bs58.decode(lastId));
@@ -93,6 +111,8 @@ export class Transaction {
// serialize `this.userdata`
if (this.userdata.length > 0) {
transactionData.writeUInt32LE(this.userdata.length, pos); // u64
pos += 8;
this.userdata.copy(transactionData, pos);
pos += this.userdata.length;
}
@@ -131,28 +151,14 @@ export class Transaction {
transactionData.copy(wireTransaction, signature.length);
return wireTransaction;
}
}
/**
* A Transaction that immediately transfers tokens
*/
export class TransferTokensTransaction extends Transaction {
constructor(from: PublicKey, to: PublicKey, amount: number) {
super();
// Forge a simple Budget Pay contract into `userdata`
// TODO: Clean this up
const userdata = Buffer.alloc(68); // 68 = serialized size of Budget enum
userdata.writeUInt32LE(60, 0);
userdata.writeUInt32LE(amount, 12); // u64
userdata.writeUInt32LE(amount, 28); // u64
const toData = bs58DecodePublicKey(to);
toData.copy(userdata, 36);
Object.assign(this, {
fee: 0,
keys: [from, to],
userdata
});
/**
* Serializes a public key into the wire format
*/
static serializePublicKey(key: PublicKey): Buffer {
const data = Buffer.from(bs58.decode(key));
assert(data.length === 32);
return data;
}
}