Skip to content

Instantly share code, notes, and snippets.

@jannikluhn
Created December 27, 2017 09:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jannikluhn/373d5d0eb782feb8b551acf1c165c812 to your computer and use it in GitHub Desktop.
Save jannikluhn/373d5d0eb782feb8b551acf1c165c812 to your computer and use it in GitHub Desktop.
Bitcoin-style UTXO system on top of Ethereum with abstracted accounts
MEMORY_COUNTER = 0
MEMORY_N_ITERATIONS = 32
MEMORY_CALLDATA_INDEX = 64
MEMORY_TOTAL_AMOUNT = 96
MEMORY_KEY = 128
MEMORY_SIGNATURE = 160
MEMORY_ADDRESS = 160
# CALLDATA:
# n inputs,
# [[input key, key signature], ...],
# n outputs,
# [[output amount, output address], ...]
#
# STORAGE:
# input key -> amount (0 if spent)
# input key + 1 -> address
# where key == sighash of output tx + index of output in tx
[
'seq',
# remember number of inputs and assert that there aren't too many
['mstore', MEMORY_N_ITERATIONS, ['calldataload', 0]],
['assert', ['lt', ['mload', MEMORY_N_ITERATIONS], ['add', 1, MAX_ITERATIONS]]],
# initialize calldata pointer to first input
['mstore', MEMORY_CALLDATA_INDEX, 32],
# for each input key
['repeat', MEMORY_COUNTER, 0, MAX_ITERATIONS, [
'seq',
['if', [
'gt',
['add', 1, ['mload', MEMORY_COUNTER]],
['mload', MEMORY_N_ITERATIONS]
], 'break'],
# copy input key and signature to memory
['calldatacopy', MEMORY_KEY, ['mload', MEMORY_CALLDATA_INDEX], 128],
['with', 'amount', ['sload', ['mload', MEMORY_KEY]], [
'with', 'total_amount', ['mload', MEMORY_TOTAL_AMOUNT], [
'seq',
# assert that unspent
['assert', ['gt', 'amount', 0]],
# check for overflow
['assert', ['gt', ['add', 'amount', 'total_amount'], 'total_amount']],
# increase total amount
['mstore', MEMORY_TOTAL_AMOUNT, ['add', 'amount', 'total_amount']],
# mark as spent
['sstore', ['mload', MEMORY_KEY], 0]
]
]],
# verify signature
[
'call',
3000,
1,
0,
MEMORY_KEY,
128,
MEMORY_ADDRESS,
32
],
['assert', [
'eq',
['mload', MEMORY_ADDRESS],
['sload', ['add', 1, ['mload', MEMORY_KEY]]]
]],
# point calldata index to next input
['mstore', MEMORY_CALLDATA_INDEX, [
'add', 128, ['mload', MEMORY_CALLDATA_INDEX]
]]
]],
# point calldata index to first output
['mstore', MEMORY_CALLDATA_INDEX, ['add', 32, ['mload', MEMORY_CALLDATA_INDEX]]],
# use sighash as first output key
['mstore', MEMORY_KEY, ['sighash']],
# remember number of outputs and assert that there aren't too many
['mstore', MEMORY_N_ITERATIONS, [
'calldataload', ['sub', ['mload', MEMORY_CALLDATA_INDEX], 32]
]],
['assert', ['lt', ['mload', MEMORY_N_ITERATIONS], ['add', 1, MAX_ITERATIONS]]],
# for each output
['repeat', MEMORY_COUNTER, 0, MAX_ITERATIONS, [
'seq',
['if', [
'gt',
['add', 1, ['mload', MEMORY_COUNTER]],
['mload', MEMORY_N_ITERATIONS]
], 'break'],
['with', 'amount', ['calldataload', ['mload', MEMORY_CALLDATA_INDEX]], [
'seq',
# verify that total amount >= amount
['assert', ['gt', ['add', 1, ['mload', MEMORY_TOTAL_AMOUNT]], 'amount']],
['with', 'key', ['mload', MEMORY_KEY], [
'seq',
# set amount
['sstore', 'key', 'amount'],
# set address (coinbase if 0)
['mstore', MEMORY_ADDRESS, [
'calldataload', ['add', 32, ['mload', MEMORY_CALLDATA_INDEX]]
]],
['if', ['eq', ['mload', MEMORY_ADDRESS], 0], [
'mstore', MEMORY_ADDRESS, ['coinbase']
]],
['sstore', ['add', 1, 'key'], ['mload', MEMORY_ADDRESS]],
]],
# reduce total amount
['mstore', MEMORY_TOTAL_AMOUNT, [
'sub', ['mload', MEMORY_TOTAL_AMOUNT], 'amount'
]]
]],
# point calldata index to next output
['mstore', MEMORY_CALLDATA_INDEX, ['add', 64, ['mload', MEMORY_CALLDATA_INDEX]]],
# increment key
['mstore', MEMORY_KEY, ['add', 1, ['mload', MEMORY_KEY]]]
]],
# assert that everything was spent
['assert', ['not', ['mload', MEMORY_TOTAL_AMOUNT]]]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment