def revert(computation: ComputationAPI) -> None: start_position, size = computation.stack_pop_ints(2) computation.extend_memory(start_position, size) computation.output = computation.memory_read_bytes(start_position, size) raise Revert(computation.output)
def return_op(computation: ComputationAPI) -> None: start_position, size = computation.stack_pop_ints(2) computation.extend_memory(start_position, size) computation.output = computation.memory_read_bytes(start_position, size) raise Halt('RETURN')
def identity(computation: ComputationAPI) -> ComputationAPI: word_count = ceil32(len(computation.msg.data)) // 32 gas_fee = constants.GAS_IDENTITY + word_count * constants.GAS_IDENTITYWORD computation.consume_gas(gas_fee, reason="Identity Precompile") computation.output = computation.msg.data_as_bytes return computation
def sha256(computation: ComputationAPI) -> ComputationAPI: word_count = ceil32(len(computation.msg.data)) // 32 gas_fee = constants.GAS_SHA256 + word_count * constants.GAS_SHA256WORD computation.consume_gas(gas_fee, reason="SHA256 Precompile") input_bytes = computation.msg.data hash = hashlib.sha256(input_bytes).digest() computation.output = hash return computation
def ripemd160(computation: ComputationAPI) -> ComputationAPI: word_count = ceil32(len(computation.msg.data)) // 32 gas_fee = constants.GAS_RIPEMD160 + word_count * constants.GAS_RIPEMD160WORD computation.consume_gas(gas_fee, reason="RIPEMD160 Precompile") # TODO: this only works if openssl is installed. hash = hashlib.new('ripemd160', computation.msg.data).digest() padded_hash = pad32(hash) computation.output = padded_hash return computation
def blake2b_fcompress(computation: ComputationAPI) -> ComputationAPI: try: parameters = extract_blake2b_parameters(computation.msg.data_as_bytes) except ValidationError as exc: raise VMError(f"Blake2b input parameter validation failure: {exc}") from exc num_rounds = parameters[0] gas_cost = GAS_COST_PER_ROUND * num_rounds computation.consume_gas(gas_cost, reason=f"Blake2b Compress Precompile w/ {num_rounds} rounds") computation.output = blake2b.compress(*parameters) return computation
def ecadd(computation: ComputationAPI, gas_cost: int = constants.GAS_ECADD) -> ComputationAPI: computation.consume_gas(gas_cost, reason='ECADD Precompile') try: result = _ecadd(computation.msg.data_as_bytes) except ValidationError: raise VMError("Invalid ECADD parameters") result_x, result_y = result result_bytes = b''.join(( pad32(int_to_big_endian(result_x.n)), pad32(int_to_big_endian(result_y.n)), )) computation.output = result_bytes return computation
def modexp(computation: ComputationAPI) -> ComputationAPI: """ https://github.com/ethereum/EIPs/pull/198 """ data = computation.msg.data_as_bytes gas_fee = _compute_modexp_gas_fee(data) computation.consume_gas(gas_fee, reason='MODEXP Precompile') result = _modexp(data) _, _, modulus_length = _extract_lengths(data) # Modulo 0 is undefined, return zero # https://math.stackexchange.com/questions/516251/why-is-n-mod-0-undefined result_bytes = b'' if modulus_length == 0 else zpad_left( int_to_big_endian(result), to_size=modulus_length) computation.output = result_bytes return computation
def ecrecover(computation: ComputationAPI) -> ComputationAPI: computation.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") data = computation.msg.data_as_bytes raw_message_hash = data[:32] message_hash = pad32r(raw_message_hash) v_bytes = pad32r(data[32:64]) v = big_endian_to_int(v_bytes) r_bytes = pad32r(data[64:96]) r = big_endian_to_int(r_bytes) s_bytes = pad32r(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