Updated deposit contract for gas efficiency
This commit is contained in:
parent
93f2ee1d13
commit
722e201109
|
@ -656,54 +656,71 @@ SECONDS_PER_DAY: constant(uint256) = 86400
|
||||||
Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], merkle_tree_index: bytes[8]})
|
Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], merkle_tree_index: bytes[8]})
|
||||||
ChainStart: event({deposit_root: bytes32, time: bytes[8]})
|
ChainStart: event({deposit_root: bytes32, time: bytes[8]})
|
||||||
|
|
||||||
deposit_tree: map(uint256, bytes32)
|
zerohashes: bytes32[32]
|
||||||
|
branch: bytes32[32]
|
||||||
deposit_count: uint256
|
deposit_count: uint256
|
||||||
full_deposit_count: uint256
|
full_deposit_count: uint256
|
||||||
|
|
||||||
|
@public
|
||||||
|
def __init__():
|
||||||
|
for i in range(31):
|
||||||
|
self.zerohashes[i+1] = sha3(concat(self.zerohashes[i], self.zerohashes[i]))
|
||||||
|
self.branch[i+1] = self.zerohashes[i+1]
|
||||||
|
|
||||||
|
@public
|
||||||
|
@constant
|
||||||
|
def get_deposit_root() -> bytes32:
|
||||||
|
root:bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
size:uint256 = self.deposit_count
|
||||||
|
for h in range(32):
|
||||||
|
if size % 2 == 1:
|
||||||
|
root = sha3(concat(self.branch[h], root))
|
||||||
|
else:
|
||||||
|
root = sha3(concat(root, self.branch[h]))
|
||||||
|
size /= 2
|
||||||
|
return root
|
||||||
|
|
||||||
@payable
|
@payable
|
||||||
@public
|
@public
|
||||||
def deposit(deposit_input: bytes[2048]):
|
def deposit(deposit_input: bytes[2048]):
|
||||||
assert msg.value >= as_wei_value(MIN_DEPOSIT_AMOUNT, "gwei")
|
assert msg.value >= as_wei_value(MIN_DEPOSIT_AMOUNT, "gwei")
|
||||||
assert msg.value <= as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei")
|
assert msg.value <= as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei")
|
||||||
|
|
||||||
index: uint256 = self.deposit_count + TWO_TO_POWER_OF_TREE_DEPTH
|
index: uint256 = self.deposit_count
|
||||||
deposit_amount: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8)
|
deposit_amount: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8)
|
||||||
deposit_timestamp: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8)
|
deposit_timestamp: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8)
|
||||||
deposit_data: bytes[2064] = concat(deposit_amount, deposit_timestamp, deposit_input)
|
deposit_data: bytes[2064] = concat(deposit_amount, deposit_timestamp, deposit_input)
|
||||||
merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8)
|
merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8)
|
||||||
|
|
||||||
log.Deposit(self.deposit_tree[1], deposit_data, merkle_tree_index)
|
|
||||||
|
|
||||||
# add deposit to merkle tree
|
# add deposit to merkle tree
|
||||||
self.deposit_tree[index] = sha3(deposit_data)
|
i: int128 = 0
|
||||||
for i in range(DEPOSIT_CONTRACT_TREE_DEPTH):
|
power_of_two: uint256 = 2
|
||||||
index /= 2
|
for _ in range(32):
|
||||||
self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1]))
|
if (index+1) % power_of_two != 0:
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
power_of_two *= 2
|
||||||
|
value:bytes32 = sha3(deposit_data)
|
||||||
|
for j in range(32):
|
||||||
|
if j < i:
|
||||||
|
value = sha3(concat(self.branch[j], value))
|
||||||
|
self.branch[j] = self.zerohashes[j]
|
||||||
|
self.branch[i] = value
|
||||||
|
|
||||||
self.deposit_count += 1
|
self.deposit_count += 1
|
||||||
|
|
||||||
|
log.Deposit(self.get_deposit_root(), deposit_data, merkle_tree_index)
|
||||||
|
|
||||||
if msg.value == as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei"):
|
if msg.value == as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei"):
|
||||||
self.full_deposit_count += 1
|
self.full_deposit_count += 1
|
||||||
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
|
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
|
||||||
timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY
|
timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY
|
||||||
chainstart_time: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8)
|
chainstart_time: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8)
|
||||||
log.ChainStart(self.deposit_tree[1], chainstart_time)
|
log.ChainStart(self.get_deposit_root(), chainstart_time)
|
||||||
|
|
||||||
@public
|
|
||||||
@constant
|
|
||||||
def get_deposit_root() -> bytes32:
|
|
||||||
return self.deposit_tree[1]
|
|
||||||
|
|
||||||
@public
|
|
||||||
@constant
|
|
||||||
def get_branch(leaf: uint256) -> bytes32[32]: # size is DEPOSIT_CONTRACT_TREE_DEPTH (symbolic const not supported)
|
|
||||||
branch: bytes32[32] # size is DEPOSIT_CONTRACT_TREE_DEPTH
|
|
||||||
index: uint256 = leaf + TWO_TO_POWER_OF_TREE_DEPTH
|
|
||||||
for i in range(DEPOSIT_CONTRACT_TREE_DEPTH):
|
|
||||||
branch[i] = self.deposit_tree[bitwise_xor(index, 1)]
|
|
||||||
index /= 2
|
|
||||||
return branch
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: to save ~10x on gas this contract uses a somewhat unintuitive progressive Merkle root calculation algo that requires only O(log(n)) storage. See https://github.com/ethereum/research/blob/master/beacon_chain_impl/progressive_merkle_tree.py for an implementation of the same algo in python tested for correctness.
|
||||||
|
|
||||||
## Beacon chain processing
|
## Beacon chain processing
|
||||||
|
|
||||||
The beacon chain is the system chain for Ethereum 2.0. The main responsibilities of the beacon chain are:
|
The beacon chain is the system chain for Ethereum 2.0. The main responsibilities of the beacon chain are:
|
||||||
|
|
Loading…
Reference in New Issue