import { NanoPow } from 'nano-pow'
import { Account } from '../account'
-import { DIFFICULTY_RECEIVE, DIFFICULTY_SEND, PREAMBLE } from '../constants'
-import { bytes, dec, hex } from '../convert'
+import { BURN_PUBLIC_KEY, DIFFICULTY_RECEIVE, DIFFICULTY_SEND, PREAMBLE } from '../constants'
+import { bytes, dec, hex, utf8 } from '../convert'
import { Blake2b } from '../crypto'
import { Rpc } from '../rpc'
import { ProcessRequest } from '../rpc/process'
_validate(block)
}
- subtype?: 'send' | 'receive' | 'change'
+ subtype?: 'change' | 'epoch' | 'receive' | 'send'
account: Account
balance: bigint
previous: Bytes
throw new TypeError('Invalid account')
}
balance ??= account.balance
- previous ??= account.frontier ?? '00'
+ previous ??= account.frontier ?? BURN_PUBLIC_KEY
representative ??= account.representative
if (typeof balance !== 'bigint' && typeof balance !== 'number' && typeof balance !== 'string') {
throw new TypeError('Account balance is unknown')
if (typeof previous !== 'string') {
throw new TypeError('Account frontier is unknown')
}
+ if (!(/^[0-9A-F]{64}$/i.test(previous))) {
+ throw new RangeError('Invalid frontier hash')
+ }
this.account = account
this.balance = convert(balance, 'raw', 'raw', 'bigint')
this.previous = hex.toBytes(previous, 32)
* @returns {Block} This block unchanged
*/
epoch (): Block {
+ const special = utf8.toHex('epoch v2 block')
+ this.link = hex.toBytes(`${special}000000000000000000000000000000000000`)
+ this.subtype = 'epoch'
return this
}
* @returns {Block} This block with balance, link, and subtype configured
*/
open (sendBlock: string | Block, amount: bigint | number | string, unit?: string): Block {
- this.previous.fill(0)
- return _receive(this, sendBlock, amount, unit)
+ const openBlock = _receive(this, sendBlock, amount, unit)
+ openBlock.previous.fill(0)
+ return openBlock
}
/**
if (this.subtype == null) {
throw new Error('Block is missing subtype. Call respective method and try again.')
}
+ if (this.subtype === 'epoch') {
+ throw new Error('Only change, receive, and send blocks can be processed.')
+ }
if (this.work == null) await this.pow()
const data: ProcessRequest = {
async: false,
&& 'contents' in body && body.contents != null && typeof body.contents === 'object'
&& 'account' in body.contents && typeof body.contents.account === 'string'
&& 'balance' in body.contents && typeof body.contents.balance === 'string'
- && 'link' in body.contents && typeof body.contents.link === 'string'
+ && 'link' in body.contents && typeof body.contents.link === 'string' && /^[0-9A-F]{64}$/i.test(body.contents.link)
&& 'link_as_account' in body.contents && typeof body.contents.link_as_account === 'string'
- && 'previous' in body.contents && typeof body.contents.previous === 'string'
+ && 'previous' in body.contents && typeof body.contents.previous === 'string' && /^[0-9A-F]{64}$/i.test(body.contents.previous)
&& 'representative' in body.contents && typeof body.contents.representative === 'string'
- && 'signature' in body.contents && typeof body.contents.signature === 'string'
+ && 'signature' in body.contents && typeof body.contents.signature === 'string' && /^[0-9A-F]{128}$/i.test(body.contents.signature)
&& 'type' in body.contents && body.contents.type === 'state'
&& 'work' in body.contents && typeof body.contents.work === 'string'
) {