Remove Budget from CLI (#11451)

* Remove support for Budget

Also:
* Make "pay" command a deprecated alias for the "transfer" command

* chore: remove budget from web3.js

* Drop Budget depedency from core

Validators no longer ship with builtin Budget
This commit is contained in:
Greg Fitzgerald
2020-08-07 16:01:51 -06:00
committed by GitHub
parent 7e25130529
commit edadd5d6d5
19 changed files with 56 additions and 2319 deletions

View File

@ -1,390 +0,0 @@
// @flow
import * as BufferLayout from 'buffer-layout';
import {Transaction} from './transaction';
import {PublicKey} from './publickey';
import {SystemProgram} from './system-program';
/**
* Represents a condition that is met by executing a `applySignature()`
* transaction
*
* @typedef {Object} SignatureCondition
* @property {string} type Must equal the string 'timestamp'
* @property {PublicKey} from Public key from which `applySignature()` will be accepted from
*/
export type SignatureCondition = {
type: 'signature',
from: PublicKey,
};
/**
* Represents a condition that is met by executing a `applyTimestamp()`
* transaction
*
* @typedef {Object} TimestampCondition
* @property {string} type Must equal the string 'timestamp'
* @property {PublicKey} from Public key from which `applyTimestamp()` will be accepted from
* @property {Date} when The timestamp that was observed
*/
export type TimestampCondition = {
type: 'timestamp',
from: PublicKey,
when: Date,
};
/**
* Represents a payment to a given public key
*
* @typedef {Object} Payment
* @property {number} amount Number of lamports
* @property {PublicKey} to Public key of the recipient
*/
export type Payment = {
amount: number,
to: PublicKey,
};
/**
* A condition that can unlock a payment
*
* @typedef {SignatureCondition|TimestampCondition} BudgetCondition
*/
export type BudgetCondition = SignatureCondition | TimestampCondition;
/**
* @private
*/
function serializePayment(payment: Payment): Buffer {
const toData = payment.to.toBuffer();
const data = Buffer.alloc(8 + toData.length);
data.writeUInt32LE(payment.amount, 0);
toData.copy(data, 8);
return data;
}
/**
* @private
*/
function serializeDate(when: Date): Buffer {
const data = Buffer.alloc(8 + 20);
data.writeUInt32LE(20, 0); // size of timestamp as u64
function iso(date) {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
return (
date.getUTCFullYear() +
'-' +
pad(date.getUTCMonth() + 1) +
'-' +
pad(date.getUTCDate()) +
'T' +
pad(date.getUTCHours()) +
':' +
pad(date.getUTCMinutes()) +
':' +
pad(date.getUTCSeconds()) +
'Z'
);
}
data.write(iso(when), 8);
return data;
}
/**
* @private
*/
function serializeCondition(condition: BudgetCondition) {
switch (condition.type) {
case 'timestamp': {
const date = serializeDate(condition.when);
const from = condition.from.toBuffer();
const data = Buffer.alloc(4 + date.length + from.length);
data.writeUInt32LE(0, 0); // Condition enum = Timestamp
date.copy(data, 4);
from.copy(data, 4 + date.length);
return data;
}
case 'signature': {
const from = condition.from.toBuffer();
const data = Buffer.alloc(4 + from.length);
data.writeUInt32LE(1, 0); // Condition enum = Signature
from.copy(data, 4);
return data;
}
default:
throw new Error(`Unknown condition type: ${condition.type}`);
}
}
/**
* Factory class for transactions to interact with the Budget program
*/
export class BudgetProgram {
/**
* Public key that identifies the Budget program
*/
static get programId(): PublicKey {
return new PublicKey('Budget1111111111111111111111111111111111111');
}
/**
* The amount of space this program requires
*/
static get space(): number {
return 128;
}
/**
* Creates a timestamp condition
*/
static timestampCondition(from: PublicKey, when: Date): TimestampCondition {
return {
type: 'timestamp',
from,
when,
};
}
/**
* Creates a signature condition
*/
static signatureCondition(from: PublicKey): SignatureCondition {
return {
type: 'signature',
from,
};
}
/**
* Generates a transaction that transfers lamports once any of the conditions are met
*/
static pay(
from: PublicKey,
program: PublicKey,
to: PublicKey,
amount: number,
...conditions: Array<BudgetCondition>
): Transaction {
const data = Buffer.alloc(1024);
let pos = 0;
data.writeUInt32LE(0, pos); // NewBudget instruction
pos += 4;
switch (conditions.length) {
case 0: {
data.writeUInt32LE(0, pos); // BudgetExpr enum = Pay
pos += 4;
{
const payment = serializePayment({amount, to});
payment.copy(data, pos);
pos += payment.length;
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [
{pubkey: to, isSigner: false, isWritable: true},
{pubkey: program, isSigner: false, isWritable: true},
],
programId: this.programId,
data: trimmedData,
});
}
case 1: {
data.writeUInt32LE(1, pos); // BudgetExpr enum = After
pos += 4;
{
const condition = conditions[0];
const conditionData = serializeCondition(condition);
conditionData.copy(data, pos);
pos += conditionData.length;
data.writeUInt32LE(0, pos); // BudgetExpr enum = Pay
pos += 4;
const paymentData = serializePayment({amount, to});
paymentData.copy(data, pos);
pos += paymentData.length;
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],
programId: this.programId,
data: trimmedData,
});
}
case 2: {
data.writeUInt32LE(2, pos); // BudgetExpr enum = Or
pos += 4;
for (let condition of conditions) {
const conditionData = serializeCondition(condition);
conditionData.copy(data, pos);
pos += conditionData.length;
data.writeUInt32LE(0, pos); // BudgetExpr enum = Pay
pos += 4;
const paymentData = serializePayment({amount, to});
paymentData.copy(data, pos);
pos += paymentData.length;
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],
programId: this.programId,
data: trimmedData,
});
}
default:
throw new Error(
`A maximum of two conditions are supported: ${conditions.length} provided`,
);
}
}
/**
* Generates a transaction that transfers lamports once both conditions are met
*/
static payOnBoth(
from: PublicKey,
program: PublicKey,
to: PublicKey,
amount: number,
condition1: BudgetCondition,
condition2: BudgetCondition,
): Transaction {
const data = Buffer.alloc(1024);
let pos = 0;
data.writeUInt32LE(0, pos); // NewBudget instruction
pos += 4;
data.writeUInt32LE(3, pos); // BudgetExpr enum = And
pos += 4;
for (let condition of [condition1, condition2]) {
const conditionData = serializeCondition(condition);
conditionData.copy(data, pos);
pos += conditionData.length;
}
data.writeUInt32LE(0, pos); // BudgetExpr enum = Pay
pos += 4;
const paymentData = serializePayment({amount, to});
paymentData.copy(data, pos);
pos += paymentData.length;
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],
programId: this.programId,
data: trimmedData,
});
}
/**
* Generates a transaction that applies a timestamp, which could enable a
* pending payment to proceed.
*/
static applyTimestamp(
from: PublicKey,
program: PublicKey,
to: PublicKey,
when: Date,
): Transaction {
const whenData = serializeDate(when);
const data = Buffer.alloc(4 + whenData.length);
data.writeUInt32LE(1, 0); // ApplyTimestamp instruction
whenData.copy(data, 4);
return new Transaction().add({
keys: [
{pubkey: from, isSigner: true, isWritable: true},
{pubkey: program, isSigner: false, isWritable: true},
{pubkey: to, isSigner: false, isWritable: true},
],
programId: this.programId,
data,
});
}
/**
* Generates a transaction that applies a signature, which could enable a
* pending payment to proceed.
*/
static applySignature(
from: PublicKey,
program: PublicKey,
to: PublicKey,
): Transaction {
const dataLayout = BufferLayout.struct([BufferLayout.u32('instruction')]);
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
instruction: 2, // ApplySignature instruction
},
data,
);
return new Transaction().add({
keys: [
{pubkey: from, isSigner: true, isWritable: true},
{pubkey: program, isSigner: false, isWritable: true},
{pubkey: to, isSigner: false, isWritable: true},
],
programId: this.programId,
data,
});
}
}

View File

@ -1,7 +1,6 @@
// @flow
export {Account} from './account';
export {BpfLoader} from './bpf-loader';
export {BudgetProgram} from './budget-program';
export {Connection} from './connection';
export {Loader} from './loader';
export {Message} from './message';