Skip to content

Instantly share code, notes, and snippets.

@s1na
Created July 2, 2019 12:40
Show Gist options
  • Save s1na/df9682fc4f9a8f4290c7d34be8ffcd2f to your computer and use it in GitHub Desktop.
Save s1na/df9682fc4f9a8f4290c7d34be8ffcd2f to your computer and use it in GitHub Desktop.
Relayer for stateless MPT-like token (scout script)
const assert = require('assert')
const { promisify } = require('util')
const BN = require('bn.js')
const Trie = require('merkle-patricia-tree')
const Account = require('ethereumjs-account').default
const StateManager = require('ethereumjs-vm/dist/state/stateManager').default
const PStateManager = require('ethereumjs-vm/dist/state/promisified').default
const { keccak256, ecsign, stripZeros } = require('ethereumjs-util')
const { encode } = require('rlp')
const prove = promisify(Trie.prove)
const verifyProof = promisify(Trie.verifyProof)
async function main () {
const rawState = new StateManager()
const state = new PStateManager(rawState)
let root = await state.getStateRoot()
console.log('empty trie root: ', root)
// Prepare "genesis" state
//const fromPubKey = '3a443d8381a6798a70c6ff9304bdc8cb0163c23211d11628fae52ef9e0dca11a001cf066d56a8156fc201cd5df8a36ef694eecd258903fca7086c1fae7441e1d'
const fromPrivateKey = Buffer.from([234, 84, 189, 197, 45, 22, 63, 136, 201, 58, 176, 97, 87, 130, 207, 113, 138, 46, 251, 158, 81, 167, 152, 154, 171, 27, 8, 6, 126, 156, 28, 95])
const addr0 = Buffer.from('2f015c60e0be116b1f0cd534704db9c92118fb6a', 'hex')
const addr1 = Buffer.from('0000000000000000000000000000000000000001', 'hex')
const acc0 = new Account()
acc0.balance = new BN('ffffff', 16).toBuffer()
const acc1 = new Account()
await state.putAccount(addr0, acc0)
await state.putAccount(addr1, acc1)
root = await state.getStateRoot()
console.log('genesis state root: ', root.toString('hex'))
// Tx data
const tx = {
from: addr0,
to: addr1,
value: new BN('00000000000000000000000000000000000000000000000000000000000000ff', 16),
nonce: new BN('0000000000000000000000000000000000000000000000000000000000000000', 16),
}
const txRlp = encode([tx.to, stripZeros(tx.value.toBuffer('be', 32)), stripZeros(tx.nonce.toBuffer('be', 32))])
const txHash = keccak256(txRlp)
const txSig = ecsign(txHash, fromPrivateKey)
// Compute witnesses for transfer:
const fromWitness = await prove(state._wrapped._trie, keccak256(tx.from))
let val = await verifyProof(root, keccak256(tx.from), fromWitness)
assert(val.equals(acc0.serialize()), "valid from witness")
const toAcc = await state.getAccount(tx.to)
const toWitness = await prove(state._wrapped._trie, keccak256(tx.to))
val = await verifyProof(root, keccak256(tx.to), toWitness)
assert(val.equals(toAcc.serialize()), "valid to witness")
// Serialize witnesses and tx data
const blockData = encode(
[
[tx.to, stripZeros(tx.value.toBuffer('be', 32)), stripZeros(tx.nonce.toBuffer('be', 32)), [stripZeros(txSig.r), stripZeros(txSig.s), txSig.v]],
fromWitness,
toWitness
]
)
console.log('block data: ', blockData.toString('hex'))
// Simulate transfering funds to compute post state root
await transfer(state, tx)
root = await state.getStateRoot()
console.log('post transfer state root: ', root.toString('hex'))
}
async function transfer (state, tx) {
let { from, to, value, nonce } = tx
assert(value.gten(0))
const fromAcc = await state.getAccount(from)
const toAcc = await state.getAccount(to)
assert(new BN(fromAcc.balance).gte(value))
assert(new BN(fromAcc.nonce).eq(nonce))
const newFromBalance = new BN(fromAcc.balance).sub(value)
fromAcc.balance = newFromBalance.toBuffer()
fromAcc.nonce = nonce.addn(1).toBuffer()
const newToBalance = new BN(toAcc.balance).add(value)
toAcc.balance = newToBalance.toBuffer()
await state.putAccount(from, fromAcc)
await state.putAccount(to, toAcc)
}
main().then(() => console.log('main done')).catch((e) => console.log(e))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment