def ecrecover(computation): computation.gas_meter.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") raw_message_hash = computation.msg.data[:32] message_hash = pad32r(raw_message_hash) v_bytes = pad32r(computation.msg.data[32:64]) v = big_endian_to_int(v_bytes) r_bytes = pad32r(computation.msg.data[64:96]) r = big_endian_to_int(r_bytes) s_bytes = pad32r(computation.msg.data[96:128]) s = big_endian_to_int(s_bytes) try: validate_lt_secpk1n(r, title="ECRecover: R") validate_lt_secpk1n(s, title="ECRecover: S") validate_lte(v, 28, title="ECRecover: V") validate_gte(v, 27, title="ECRecover: V") except ValidationError: return computation canonical_v = v - 27 try: signature = keys.Signature(vrs=(canonical_v, r, s)) public_key = signature.recover_public_key_from_msg_hash(message_hash) except BadSignature: return computation address = public_key.to_canonical_address() padded_address = pad32(address) computation.output = padded_address return computation
def __init__(self, gas, to, sender, value, data, code, depth=0, create_address=None, code_address=None, should_transfer_value=True, is_static=False): validate_uint256(gas, title="Message.gas") self.gas = gas if to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(to, title="Message.to") self.to = to validate_canonical_address(sender, title="Message.sender") self.sender = sender validate_uint256(value, title="Message.value") self.value = value validate_is_bytes(data, title="Message.data") self.data = data validate_is_integer(depth, title="Message.depth") validate_gte(depth, minimum=0, title="Message.depth") self.depth = depth validate_is_bytes(code, title="Message.code") self.code = code if create_address is not None: validate_canonical_address(create_address, title="Message.storage_address") self.storage_address = create_address if code_address is not None: validate_canonical_address(code_address, title="Message.code_address") self.code_address = code_address validate_is_boolean(should_transfer_value, title="Message.should_transfer_value") self.should_transfer_value = should_transfer_value validate_is_boolean(is_static, title="Message.is_static") self.is_static = is_static
def validate(self): super().validate() # includes validation of `(int_)gas_price` validate_canonical_address(self.destination, "Transaction.destination") validate_uint256(self.value, "Transaction.value") validate_uint256(self.min_block, "Transaction.min_block") validate_uint256(self.max_block, "Transaction.max_block") validate_uint256(self.nonce, "Transaction.nonce") validate_is_bytes(self.msg_data, "Transaction.msg_data") validate_uint256(self.v, title="Transaction.v") validate_uint256(self.r, title="Transaction.r") validate_uint256(self.s, title="Transaction.s") validate_lt_secpk1n(self.r, title="Transaction.r") validate_gte(self.r, minimum=1, title="Transaction.r") validate_lt_secpk1n(self.s, title="Transaction.s") validate_gte(self.s, minimum=1, title="Transaction.s") validate_gte(self.v, minimum=27, title="Transaction.v") validate_lte(self.v, maximum=28, title="Transaction.v")
def validate(self): validate_uint256(self.nonce, title="Transaction.nonce") validate_uint256(self.gas_price, title="Transaction.gas_price") validate_uint256(self.gas, title="Transaction.gas") if self.to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(self.to, title="Transaction.to") validate_uint256(self.value, title="Transaction.value") validate_is_bytes(self.data, title="Transaction.data") validate_uint256(self.v, title="Transaction.v") validate_uint256(self.r, title="Transaction.r") validate_uint256(self.s, title="Transaction.s") validate_lt_secpk1n(self.r, title="Transaction.r") validate_gte(self.r, minimum=1, title="Transaction.r") validate_lt_secpk1n(self.s, title="Transaction.s") validate_gte(self.s, minimum=1, title="Transaction.s") validate_gte(self.v, minimum=self.v_min, title="Transaction.v") validate_lte(self.v, maximum=self.v_max, title="Transaction.v") super(FrontierTransaction, self).validate()
def validate(self): validate_uint256(self.nonce, title="Transaction.nonce") validate_uint256(self.gas_price, title="Transaction.gas_price") validate_uint256(self.gas, title="Transaction.gas") if self.to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(self.to, title="Transaction.to") validate_uint256(self.value, title="Transaction.value") validate_is_bytes(self.data, title="Transaction.data") validate_uint256(self.v, title="Transaction.v") validate_uint256(self.r, title="Transaction.r") validate_uint256(self.s, title="Transaction.s") validate_lt_secpk1n(self.r, title="Transaction.r") validate_gte(self.r, minimum=1, title="Transaction.r") validate_lt_secpk1n(self.s, title="Transaction.s") validate_gte(self.s, minimum=1, title="Transaction.s") validate_gte(self.v, minimum=27, title="Transaction.v") validate_lte(self.v, maximum=28, title="Transaction.v") super(FrontierTransaction, self).validate()
def validate(self): validate_uint256(self.nonce) validate_uint256(self.gas_price) validate_uint256(self.gas) if self.to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(self.to) validate_uint256(self.value) validate_is_bytes(self.data) validate_uint256(self.v) validate_uint256(self.r) validate_uint256(self.s) validate_lt_secpk1n(self.r) validate_gte(self.r, minimum=1) validate_lt_secpk1n(self.s) validate_gte(self.s, minimum=1) validate_gte(self.v, minimum=27) validate_lte(self.v, maximum=28) super(FrontierTransaction, self).validate()
def _generate_vm_configuration( *fork_start_blocks: ForkStartBlocks, dao_start_block: Union[int, bool] = None ) -> Generator[VMStartBlock, None, None]: # noqa: E501 """ fork_start_blocks should be 2-tuples of (start_block, fork_name_or_vm_class) dao_start_block determines whether the Homestead fork will support the DAO fork and if so, at what block. - dao_start_block = None: perform the DAO fork at the same block as the Homestead start block. - dao_start_block = False: do not perform the DAO fork. - dao_start_block = <int>: perform the DAO fork at the given block number. """ # if no configuration was passed in, initialize the chain with the *latest* # Mainnet VM rules active at block 0. if not fork_start_blocks: yield (0, last(MAINNET_VMS.values())) return # Validate that there are no fork names which are not represented in the # mainnet chain. fork_names = set(fork_name for _, fork_name in fork_start_blocks if isinstance(fork_name, str)) unknown_forks = sorted(fork_names.difference(MAINNET_VMS.keys())) if unknown_forks: raise ValidationError( "Configuration contains unknown forks: {0}".format(unknown_forks)) # Validate that *if* an explicit value was passed in for dao_start_block # that the Homestead fork rules are part of the VM configuration. if dao_start_block is not None and 'homestead' not in fork_names: raise ValidationError( "The `dao_start_block` parameter is only valid for the 'homestead' " "fork rules. The 'homestead' VM was not included in the provided " "fork configuration") # If no VM is set to start at block 0, default to the frontier VM start_blocks = set(start_block for start_block, _ in fork_start_blocks) if 0 not in start_blocks: yield 0, MAINNET_VMS['frontier'] ordered_fork_start_blocks = sorted(fork_start_blocks, key=operator.itemgetter(0)) # Iterate over the parameters, generating a tuple of 2-tuples in the form: # (start_block, vm_class) for start_block, fork in ordered_fork_start_blocks: if isinstance(fork, type) and issubclass(fork, BaseVM): vm_class = fork elif isinstance(fork, str): vm_class = MAINNET_VMS[fork] else: raise Exception("Invariant: unreachable code path") if issubclass(vm_class, HomesteadVM): if dao_start_block is False: yield (start_block, vm_class.configure(support_dao_fork=False)) elif dao_start_block is None: yield (start_block, vm_class.configure(dao_fork_block_number=start_block)) elif isinstance(dao_start_block, int): validate_gte(dao_start_block, start_block) yield (start_block, vm_class.configure( dao_fork_block_number=dao_start_block)) else: raise Exception("Invariant: unreachable code path") else: yield (start_block, vm_class)
def test_validate_gte(value, minimum, is_valid): if is_valid: validate_gte(value, minimum) else: with pytest.raises(ValidationError): validate_gte(value, minimum)