diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se')
-rw-r--r-- | Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se new file mode 100644 index 000000000..1e466a355 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se @@ -0,0 +1,166 @@ +# Exists in state: +# (i) last committed block +# (ii) chain of uncommitted blocks (linear only) +# (iii) transactions, each tx with an associated block number +# +# Uncommitted block = +# [ numtxs, numkvs, tx1 (N words), tx2 (N words) ..., [k1, v1], [k2, v2], [k3, v3] ... ] +# +# Block checking process +# +# Suppose last committed state is m +# Last uncommitted state is n +# Contested block is b +# +# 1. Temporarily apply all state transitions from +# m to b +# 2. Run code, get list of changes +# 3. Check is list of changes matches deltas +# * if yes, do nothing +# * if no, set last uncommitted state to pre-b +# +# Storage variables: +# +# Last committed block: 0 +# Last uncommitted block: 1 +# Contract holding code: 2 +# Uncommitted map: 3 +# Transaction length (parameter): 4 +# Block b: 2^160 + b * 2^40: +# + 1: submission blknum +# + 2: submitter +# + 3: data in uncommitted block format above +# Last committed storage: +# sha3(k): index k + +# Initialize: [0, c, txlength], set address of the code-holding contract and the transaction +# length +if not contract.storage[2]: + contract.storage[2] = msg.data[1] + contract.storage[4] = msg.data[2] + stop + +# Sequentially commit all uncommitted blocks that are more than 1000 mainchain-blocks old +last_committed_block = contract.storage[0] +last_uncommitted_block = contract.storage[1] +lcb_storage_index = 2^160 + last_committed_block * 2^40 +while contract.storage[lcb_storage_index + 1] < block.number - 1000 and last_committed_block < last_uncommitted_block: + kvpairs = contract.storage[lcb_storage_index] + i = 0 + while i < kvpairs: + k = contract.storage[lcb_storage_index + 3 + i * 2] + v = contract.storage[lcb_storage_index + 4 + i * 2] + contract.storage[sha3(k)] = v + i += 1 + last_committed_block += 1 + lcb_storage_index += 2^40 +contract.storage[0] = last_committed_block + + +# Propose block: [ 0, block number, data in block format above ... ] +if msg.data[0] == 0: + blknumber = msg.data[1] + # Block number must be correct + if blknumber != contract.storage[1]: + stop + # Deposit requirement + if msg.value < 10^19: + stop + # Store the proposal in storage as + # [ 0, main-chain block number, sender, block data...] + start_index = 2^160 + blknumber * 2^40 + numkvs = (msg.datasize - 2) / 2 + contract.storage[start_index + 1] = block.number + 1ontract.storage[start_index + 2] = msg.sender + i = 0 + while i < msg.datasize - 2: + contract.storage[start_index + 3 + i] = msg.data[2 + i] + i += 1 + contract.storage[1] = blknumber + 1 + +# Challenge block: [ 1, b ] +elif msg.data[0] == 1: + blknumber = msg.data[1] + txwidth = contract.storage[4] + last_uncommitted_block = contract.storage[1] + last_committed_block = contract.storage[0] + # Cannot challenge nonexistent or committed blocks + if blknumber <= last_uncommitted_block or blknumber > last_committed_block: + stop + # Create a contract to serve as a map that maintains keys and values + # temporarily + tempstore = create('map.se') + contract.storage[3] = tempstore + # Unquestioningly apply the state transitions from the last committed block + # up to b + b = last_committed_block + cur_storage_index = 2^160 + last_committed_block * 2^40 + while b < blknumber: + numtxs = contract.storage[cur_storage_index + 3] + numkvs = contract.storage[cur_storage_index + 4] + kv0index = cur_storage_index + 5 + numtxs * txwidth + i = 0 + while i < numkvs: + k = contract.storage[kv0index + i * 2] + v = contract.storage[kx0index + i * 2 + 1] + call(tempstore, [1, k, v], 3) + i += 1 + b += 1 + cur_storage_index += 2^40 + # Run the actual code, and see what state transitions it outputs + # The way that the code is expected to work is to: + # + # (1) take as input the list of transactions (the contract should + # use msg.datasize to determine how many txs there are, and it should + # be aware of the value of txwidth) + # (2) call this contract with [2, k] to read current state data + # (3) call this contract with [3, k, v] to write current state data + # (4) return as output a list of all state transitions that it made + # in the form [kvcount, k1, v1, k2, v2 ... ] + # + # The reason for separating (2) from (3) is that sometimes the state + # transition may end up changing a given key many times, and we don't + # need to inefficiently store that in storage + numkvs = contract.storage[cur_storage_index + 3] + numtxs = contract.storage[cur_storage_index + 4] + # Populate input array + inpwidth = numtxs * txwidth + inp = array(inpwidth) + i = 0 + while i < inpwidth: + inp[i] = contract.storage[cur_storage_index + 5 + i] + i += 1 + out = call(contract.storage[2], inp, inpwidth, numkvs * 2 + 1) + # Check that the number of state transitions is the same + if out[0] != kvcount: + send(msg.sender, 10^19) + contract.storage[0] = last_committed_block + stop + kv0index = cur_storage_index + 5 + numtxs * txwidth + i = 0 + while i < kvcount: + # Check that each individual state transition matches + k = contract.storage[kv0index + i * 2 + 1] + v = contract.storage[kv0index + i * 2 + 2] + if k != out[i * 2 + 1] or v != out[i * 2 + 2]: + send(msg.sender, 10^19) + contract.storage[0] = last_committed_block + stop + i += 1 + # Suicide tempstore + call(tempstore, 2) + + +# Read data [2, k] +elif msg.data[0] == 2: + tempstore = contract.storage[3] + o = call(tempstore, [0, msg.data[1]], 2, 2) + if o[0]: + return(o[1]) + else: + return contract.storage[sha3(msg.data[1])] + +# Write data [3, k, v] +elif msg.data[0] == 3: + tempstore = contract.storage[3] + call(tempstore, [1, msg.data[1], msg.data[2]], 3, 2) |