github.com/prysmaticlabs/prysm@v1.4.4/contracts/deposit-contract/depositContract.v.py (about)

     1  # Vyper target 0.1.0b12
     2  MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000  # Gwei
     3  DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
     4  MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1
     5  PUBKEY_LENGTH: constant(uint256) = 48  # bytes
     6  WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32  # bytes
     7  SIGNATURE_LENGTH: constant(uint256) = 96  # bytes
     8  AMOUNT_LENGTH: constant(uint256) = 8  # bytes
     9  
    10  DepositEvent: event({
    11      pubkey: bytes[48],
    12      withdrawal_credentials: bytes[32],
    13      amount: bytes[8],
    14      signature: bytes[96],
    15      index: bytes[8],
    16  })
    17  
    18  branch: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
    19  deposit_count: uint256
    20  drain_address: public(address)
    21  
    22  # Compute hashes in empty sparse Merkle tree
    23  zero_hashes: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
    24  @public
    25  def __init__(_drain_address: address):
    26      self.drain_address = _drain_address
    27      for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1):
    28          self.zero_hashes[i + 1] = sha256(concat(self.zero_hashes[i], self.zero_hashes[i]))
    29  
    30  @private
    31  @constant
    32  def to_little_endian_64(value: uint256) -> bytes[8]:
    33      # Reversing bytes using bitwise uint256 manipulations
    34      # Note: array accesses of bytes[] are not currently supported in Vyper
    35      # Note: this function is only called when `value < 2**64`
    36      y: uint256 = 0
    37      x: uint256 = value
    38      for _ in range(8):
    39          y = shift(y, 8)
    40          y = y + bitwise_and(x, 255)
    41          x = shift(x, -8)
    42      return slice(convert(y, bytes32), start=24, len=8)
    43  
    44  
    45  @public
    46  @constant
    47  def get_deposit_root() -> bytes32:
    48      zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
    49      node: bytes32 = zero_bytes32
    50      size: uint256 = self.deposit_count
    51      for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
    52          if bitwise_and(size, 1) == 1:  # More gas efficient than `size % 2 == 1`
    53              node = sha256(concat(self.branch[height], node))
    54          else:
    55              node = sha256(concat(node, self.zero_hashes[height]))
    56          size /= 2
    57      return sha256(concat(node, self.to_little_endian_64(self.deposit_count), slice(zero_bytes32, start=0, len=24)))
    58  
    59  
    60  @public
    61  @constant
    62  def get_deposit_count() -> bytes[8]:
    63      return self.to_little_endian_64(self.deposit_count)
    64  
    65  
    66  @payable
    67  @public
    68  def deposit(pubkey: bytes[PUBKEY_LENGTH],
    69              withdrawal_credentials: bytes[WITHDRAWAL_CREDENTIALS_LENGTH],
    70              signature: bytes[SIGNATURE_LENGTH],
    71              deposit_data_root: bytes32):
    72      # Avoid overflowing the Merkle tree (and prevent edge case in computing `self.branch`)
    73      assert self.deposit_count < MAX_DEPOSIT_COUNT
    74  
    75      # Check deposit amount
    76      deposit_amount: uint256 = msg.value / as_wei_value(1, "gwei")
    77      assert deposit_amount >= MIN_DEPOSIT_AMOUNT
    78  
    79      # Length checks to facilitate formal verification (see https://github.com/ethereum/eth2.0-specs/pull/1362/files#r320361859)
    80      assert len(pubkey) == PUBKEY_LENGTH
    81      assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH
    82      assert len(signature) == SIGNATURE_LENGTH
    83  
    84      # Emit `DepositEvent` log
    85      amount: bytes[8] = self.to_little_endian_64(deposit_amount)
    86      log.DepositEvent(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count))
    87  
    88      # Compute deposit data root (`DepositData` hash tree root)
    89      zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
    90      pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes32, start=0, len=64 - PUBKEY_LENGTH)))
    91      signature_root: bytes32 = sha256(concat(
    92          sha256(slice(signature, start=0, len=64)),
    93          sha256(concat(slice(signature, start=64, len=SIGNATURE_LENGTH - 64), zero_bytes32)),
    94      ))
    95      node: bytes32 = sha256(concat(
    96          sha256(concat(pubkey_root, withdrawal_credentials)),
    97          sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)),
    98      ))
    99      # Verify computed and expected deposit data roots match
   100      assert node == deposit_data_root
   101  
   102      # Add deposit data root to Merkle tree (update a single `branch` node)
   103      self.deposit_count += 1
   104      size: uint256 = self.deposit_count
   105      for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
   106          if bitwise_and(size, 1) == 1:  # More gas efficient than `size % 2 == 1`
   107              self.branch[height] = node
   108              break
   109          node = sha256(concat(self.branch[height], node))
   110          size /= 2
   111  
   112  # !!! DEBUG ONLY !!!
   113  # This method is NOT part of the final ETH2.0 deposit contract, but we use it
   114  # to recover test funds.
   115  @public
   116  def drain():
   117      send(self.drain_address, self.balance)