From: Chris Duncan Date: Tue, 5 Aug 2025 21:50:50 +0000 (-0700) Subject: Create initial chaining functions for Block class. X-Git-Tag: v0.10.5~43^2~79 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=797b35f980a253f09f425cdf5bd9561870c1ca3f;p=libnemo.git Create initial chaining functions for Block class. --- diff --git a/src/lib/block.ts b/src/lib/block.ts index f97215b..b70e1d7 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -17,9 +17,9 @@ import { Rpc } from './rpc' abstract class Block { account: Account type: 'state' = 'state' - abstract subtype: 'send' | 'receive' | 'change' + abstract subtype?: 'send' | 'receive' | 'change' abstract previous: string - abstract representative: Account + abstract representative?: Account abstract balance: bigint abstract link: string abstract signature?: string @@ -44,6 +44,9 @@ abstract class Block { * @returns {Promise} Block data hashed to a byte array */ get hash (): string { + if (this.representative == null) { + throw new Error('Block hash missing representative') + } const data = [ PREAMBLE, this.account.publicKey, @@ -67,7 +70,7 @@ abstract class Block { "type": this.type, "account": this.account.address, "previous": this.previous, - "representative": this.representative.address, + "representative": this.representative?.address ?? '', "balance": this.balance.toString(), "link": this.link, "signature": this.signature ?? '', @@ -75,6 +78,24 @@ abstract class Block { } } + /** + * Set the subtype and link to configure this as a change representative block. + * + * @returns {Block} This block so that additional calls can be chained + */ + change (): Block { + if (this.subtype != null) { + throw new Error(`Block is already configured as ${this.subtype}`) + } + try { + this.subtype = 'change' + return this + } catch (err) { + this.subtype = undefined + throw new TypeError('Failed to configure send block', { cause: err }) + } + } + /** * Calculates proof-of-work using a pool of Web Workers. * @@ -126,6 +147,59 @@ abstract class Block { return res.hash } + /** + * Set the amount of nano that this block will send to a recipient account. + * + * @param {bigint} amount - Amount to send to recipient in raw + * @returns {Block} This block so that additional calls can be chained + */ + send (amount: bigint): Block + /** + * Set the amount of nano that this block will send to a recipient account. + * + * @param {number} amount - Amount to send to recipient in nano (10³⁰ raw) + * @returns {Block} This block so that additional calls can be chained + */ + send (amount: number): Block + /** + * Set the amount of nano that this block will send to a recipient account. + * + * @param {string} amount - Amount to send to recipient in raw + * @returns {Block} This block so that additional calls can be chained + */ + send (amount: string): Block + send (amount: unknown): Block { + const currentBalance = this.balance + try { + if (this.subtype != null) { + throw new Error(`Block is already configured as ${this.subtype}`) + } + this.subtype = 'send' + switch (typeof amount) { + case 'bigint': { + this.balance -= amount + break + } + case 'number': { + this.balance -= BigInt(amount) * (1n << 30n) + break + } + case 'string': { + this.balance -= BigInt(amount) + break + } + default: { + throw new TypeError('Invalid amount') + } + } + return this + } catch (err) { + this.subtype = undefined + this.balance = currentBalance + throw new TypeError('Failed to configure send block', { cause: err }) + } + } + /** * Signs the block using a private key. If successful, the result is stored in * the object's `signature` property. @@ -176,6 +250,52 @@ abstract class Block { } } + /** + * Set the recipient of a send block or the target representative of a change + * block. + * + * @param {string} account - Address or public key of Account to target + * @returns {Block} This block so that additional calls can be chained + */ + to (account: string): Block + /** + * Set the recipient of a send block or the target representative of a change + * block. + * + * @param {Account} account - Account to target + * @returns {Block} This block so that additional calls can be chained + */ + to (account: Account): Block + to (account: unknown): Block { + try { + if (typeof account !== 'string' && !(account instanceof Account)) { + throw new TypeError('Invalid account') + } + switch (this.subtype) { + case 'change': { + this.link = Account.import(BURN_ADDRESS).publicKey + this.representative = (typeof account === 'string') + ? Account.import(account) + : account + break + } + case 'send': { + this.link = (typeof account === 'string') + ? Account.import(account).publicKey + : account.publicKey + this.representative = this.account.representative + break + } + default: { + throw new TypeError('Invalid subtype') + } + } + return this + } catch (err) { + throw new Error('Failed to change to, or send to, an Account', { cause: err }) + } + } + /** * Verifies the signature of the block. If a key is not provided, the public * key of the block's account will be used if it exists.