def apply_xshard_desposit(state, deposit, gas_used_start): state.logs = [] state.suicides = [] state.refunds = 0 state.full_shard_key = deposit.to_address.full_shard_key state.delta_token_balance( deposit.from_address.recipient, deposit.transfer_token_id, deposit.value ) message_data = vm.CallData( [safe_ord(x) for x in deposit.message_data], 0, len(deposit.message_data) ) message = vm.Message( deposit.from_address.recipient, deposit.to_address.recipient, deposit.value, deposit.gas_remained, message_data, code_address=deposit.to_address.recipient, from_full_shard_key=deposit.from_address.full_shard_key, to_full_shard_key=deposit.to_address.full_shard_key, tx_hash=deposit.tx_hash, transfer_token_id=deposit.transfer_token_id, gas_token_id=deposit.gas_token_id, ) # MESSAGE ext = VMExt( state, sender=deposit.from_address.recipient, gas_price=deposit.gas_price ) return apply_transaction_message( state, message, ext, should_create_contract=deposit.create_contract, gas_used_start=gas_used_start, is_cross_shard=True, contract_address=deposit.to_address.recipient if deposit.create_contract else b"", )
def create_contract(ext, msg): log_msg.debug("CONTRACT CREATION") if msg.is_cross_shard: return 0, msg.gas, b"" code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if ext.post_constantinople_hardfork() and msg.sender == null_address: msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, 0) # msg.to = sha3(msg.sender + code)[12:] else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, nonce) if ext.post_metropolis_hardfork() and (ext.get_nonce(msg.to) or len(ext.get_code(msg.to))): log_msg.debug("CREATING CONTRACT ON TOP OF EXISTING CONTRACT") return 0, 0, b"" b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b"") # ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1 if ext.post_spurious_dragon_hardfork() else 0) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug( "CONTRACT CREATION FINISHED", res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), ) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576 or not ext.post_spurious_dragon_hardfork()): gas -= gcost else: dat = [] log_msg.debug( "CONTRACT CREATION FAILED", have=gas, want=gcost, block_number=ext.block_number, ) if ext.post_homestead_hardfork(): ext.revert(snapshot) return 0, 0, b"" ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug("SETTING CODE", addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash): """tx_wrapper_hash is the hash for quarkchain.core.Transaction TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly """ state.logs = [] state.suicides = [] state.refunds = 0 validate_transaction(state, tx) state.full_shard_key = tx.to_full_shard_key intrinsic_gas = tx.intrinsic_gas_used log_tx.debug("TX NEW", txdict=tx.to_dict()) # start transacting ################# if tx.sender != null_address: state.increment_nonce(tx.sender) # part of fees should go to root chain miners local_fee_rate = (1 - state.qkc_config.reward_tax_rate if state.qkc_config else Fraction(1)) # buy startgas assert state.get_balance(tx.sender) >= tx.startgas * tx.gasprice state.delta_balance(tx.sender, -tx.startgas * tx.gasprice) message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data)) message = vm.Message( tx.sender, tx.to, tx.value, tx.startgas - intrinsic_gas, message_data, code_address=tx.to, is_cross_shard=tx.is_cross_shard, from_full_shard_key=tx.from_full_shard_key, to_full_shard_key=tx.to_full_shard_key, tx_hash=tx_wrapper_hash, ) # MESSAGE ext = VMExt(state, tx) contract_address = b"" if tx.to != b"": result, gas_remained, data = apply_msg(ext, message) else: # CREATE result, gas_remained, data = create_contract(ext, message) contract_address = (data if data else b"" ) # data could be [] when vm failed execution assert gas_remained >= 0 log_tx.debug("TX APPLIED", result=result, gas_remained=gas_remained, data=data) gas_used = tx.startgas - gas_remained # pay CORRECT tx fee (after tax) to coinbase so that each step of state is accurate # Transaction failed if not result: log_tx.debug( "TX FAILED", reason="out of gas", startgas=tx.startgas, gas_remained=gas_remained, ) state.delta_balance(tx.sender, tx.gasprice * gas_remained) fee = (tx.gasprice * gas_used * local_fee_rate.numerator // local_fee_rate.denominator) state.delta_balance(state.block_coinbase, fee) state.block_fee += tx.gasprice * gas_used output = b"" success = 0 # Transaction success else: log_tx.debug("TX SUCCESS", data=data) state.refunds += len(set(state.suicides)) * opcodes.GSUICIDEREFUND if state.refunds > 0: log_tx.debug("Refunding", gas_refunded=min(state.refunds, gas_used // 2)) gas_remained += min(state.refunds, gas_used // 2) gas_used -= min(state.refunds, gas_used // 2) state.refunds = 0 # sell remaining gas state.delta_balance(tx.sender, tx.gasprice * gas_remained) # if x-shard, reserve part of the gas for the target shard miner fee = (tx.gasprice * (gas_used - (opcodes.GTXXSHARDCOST if tx.is_cross_shard else 0)) * local_fee_rate.numerator // local_fee_rate.denominator) state.delta_balance(state.block_coinbase, fee) state.block_fee += fee if tx.to: output = bytearray_to_bytestr(data) else: output = data success = 1 # TODO: check if the destination address is correct, and consume xshard gas of the state # the xshard gas and fee is consumed by destination shard block state.gas_used += gas_used # Clear suicides suicides = state.suicides state.suicides = [] for s in suicides: state.set_balance(s, 0) state.del_account(s) # Pre-Metropolis: commit state after every tx if not state.is_METROPOLIS() and not SKIP_MEDSTATES: state.commit() # Construct a receipt r = mk_receipt(state, success, state.logs, contract_address, state.full_shard_key) state.logs = [] state.add_receipt(r) state.set_param("bloom", state.bloom | r.bloom) state.set_param("txindex", state.txindex + 1) return success, output
def create_contract(ext, msg, contract_recipient=b"", salt=None): log_msg.debug("CONTRACT CREATION") if msg.transfer_token_id != ext.default_chain_token: # TODODLL calling smart contract with non QKC transfer_token_id is not supported return 0, msg.gas, b"" code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if contract_recipient != b"": # apply xshard deposit, where contract address has already been specified msg.to = contract_recipient elif salt is not None: # create2 msg.to = mk_contract_address2(msg.sender, salt, utils.sha3(code)) else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(msg.sender, nonce, msg.to_full_shard_key) if ext.get_nonce(msg.to) or len(ext.get_code(msg.to)): log_msg.debug("CREATING CONTRACT ON TOP OF EXISTING CONTRACT") return 0, 0, b"" if ext.account_exists(msg.to): ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b"") ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1) ext.reset_storage(msg.to) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug( "CONTRACT CREATION FINISHED", res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), ) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576): gas -= gcost else: log_msg.debug( "CONTRACT CREATION FAILED", have=gas, want=gcost, block_number=ext.block_number, ) ext.revert(snapshot) return 0, 0, b"" ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug("SETTING CODE", addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash): """tx_wrapper_hash is the hash for quarkchain.core.Transaction TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly """ state.logs = [] state.suicides = [] state.refunds = 0 validate_transaction(state, tx) state.full_shard_key = tx.to_full_shard_key intrinsic_gas = tx.intrinsic_gas_used log_tx.debug("TX NEW", txdict=tx.to_dict()) # start transacting ################# state.increment_nonce(tx.sender) # part of fees should go to root chain miners local_fee_rate = (1 - state.qkc_config.reward_tax_rate if state.qkc_config else Fraction(1)) # buy startgas gasprice, refund_rate = tx.gasprice, 100 # convert gas if using non-genesis native token if gasprice != 0 and tx.gas_token_id != state.genesis_token: refund_rate, converted_genesis_token_gas_price = pay_native_token_as_gas( state, tx.gas_token_id, tx.startgas, tx.gasprice) # guaranteed by validation check(converted_genesis_token_gas_price > 0) gasprice = converted_genesis_token_gas_price contract_addr = SystemContract.GENERAL_NATIVE_TOKEN.addr() # guaranteed by validation check( state.deduct_value( contract_addr, state.genesis_token, tx.startgas * converted_genesis_token_gas_price, )) state.delta_token_balance(contract_addr, tx.gas_token_id, tx.startgas * tx.gasprice) check( state.deduct_value(tx.sender, tx.gas_token_id, tx.startgas * tx.gasprice)) message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data)) message = vm.Message( tx.sender, tx.to, tx.value, tx.startgas - intrinsic_gas, message_data, code_address=tx.to, from_full_shard_key=tx.from_full_shard_key if not tx.is_testing else None, to_full_shard_key=tx.to_full_shard_key if not tx.is_testing else None, tx_hash=tx_wrapper_hash, transfer_token_id=tx.transfer_token_id, # always genesis token for gas token gas_token_id=state.genesis_token, ) # MESSAGE ext = VMExt(state, tx.sender, gasprice) contract_address = b"" if not tx.is_cross_shard: return apply_transaction_message(state, message, ext, tx.to == b"", intrinsic_gas, refund_rate=refund_rate) # handle xshard local_gas_used = intrinsic_gas remote_gas_reserved = 0 if transfer_failure_by_posw_balance_check(ext, message): success = 0 # Currently, burn all gas local_gas_used = tx.startgas elif tx.to == b"": check(state.deduct_value(tx.sender, tx.transfer_token_id, tx.value)) remote_gas_reserved = tx.startgas - intrinsic_gas ext.add_cross_shard_transaction_deposit( quarkchain.core.CrossShardTransactionDeposit( tx_hash=tx_wrapper_hash, from_address=quarkchain.core.Address(tx.sender, tx.from_full_shard_key), to_address=quarkchain.core.Address( mk_contract_address(tx.sender, state.get_nonce(tx.sender), tx.from_full_shard_key), tx.to_full_shard_key, ), value=tx.value, # convert to genesis token and use converted gas price gas_token_id=state.genesis_token, gas_price=gasprice, transfer_token_id=tx.transfer_token_id, message_data=tx.data, create_contract=True, gas_remained=remote_gas_reserved, refund_rate=refund_rate, )) success = 1 else: check(state.deduct_value(tx.sender, tx.transfer_token_id, tx.value)) if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP): remote_gas_reserved = tx.startgas - intrinsic_gas ext.add_cross_shard_transaction_deposit( quarkchain.core.CrossShardTransactionDeposit( tx_hash=tx_wrapper_hash, from_address=quarkchain.core.Address(tx.sender, tx.from_full_shard_key), to_address=quarkchain.core.Address(tx.to, tx.to_full_shard_key), value=tx.value, # convert to genesis token and use converted gas price gas_token_id=state.genesis_token, gas_price=gasprice, transfer_token_id=tx.transfer_token_id, message_data=tx.data, create_contract=False, gas_remained=remote_gas_reserved, refund_rate=refund_rate, )) success = 1 gas_remained = tx.startgas - local_gas_used - remote_gas_reserved _refund(state, message, ext.tx_gasprice * gas_remained, refund_rate) # if x-shard, reserve part of the gas for the target shard miner for fee fee = (ext.tx_gasprice * (local_gas_used - (opcodes.GTXXSHARDCOST if success else 0)) * local_fee_rate.numerator // local_fee_rate.denominator) state.delta_token_balance(state.block_coinbase, state.genesis_token, fee) add_dict(state.block_fee_tokens, {state.genesis_token: fee}) output = [] state.gas_used += local_gas_used if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP): state.gas_used -= opcodes.GTXXSHARDCOST if success else 0 # Construct a receipt r = mk_receipt(state, success, state.logs, contract_address, state.full_shard_key) state.logs = [] state.add_receipt(r) return success, output
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash): """tx_wrapper_hash is the hash for quarkchain.core.Transaction TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly """ state.logs = [] state.suicides = [] state.refunds = 0 validate_transaction(state, tx) state.full_shard_key = tx.to_full_shard_key intrinsic_gas = tx.intrinsic_gas_used log_tx.debug("TX NEW", txdict=tx.to_dict()) # start transacting ################# state.increment_nonce(tx.sender) # part of fees should go to root chain miners local_fee_rate = (1 - state.qkc_config.reward_tax_rate if state.qkc_config else Fraction(1)) # buy startgas assert (state.get_balance(tx.sender, token_id=tx.gas_token_id) >= tx.startgas * tx.gasprice) state.delta_token_balance(tx.sender, tx.gas_token_id, -tx.startgas * tx.gasprice) message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data)) message = vm.Message( tx.sender, tx.to, tx.value, tx.startgas - intrinsic_gas, message_data, code_address=tx.to, from_full_shard_key=tx.from_full_shard_key if not tx.is_testing else None, to_full_shard_key=tx.to_full_shard_key if not tx.is_testing else None, tx_hash=tx_wrapper_hash, transfer_token_id=tx.transfer_token_id, gas_token_id=tx.gas_token_id, ) # MESSAGE ext = VMExt(state, tx.sender, tx.gasprice) contract_address = b"" if tx.is_cross_shard: local_gas_used = intrinsic_gas remote_gas_reserved = 0 if transfer_failure_by_posw_balance_check(ext, message): success = 0 # Currently, burn all gas local_gas_used = tx.startgas elif tx.to == b"": state.delta_token_balance(tx.sender, tx.transfer_token_id, -tx.value) remote_gas_reserved = tx.startgas - intrinsic_gas ext.add_cross_shard_transaction_deposit( quarkchain.core.CrossShardTransactionDeposit( tx_hash=tx_wrapper_hash, from_address=quarkchain.core.Address( tx.sender, tx.from_full_shard_key), to_address=quarkchain.core.Address( mk_contract_address( tx.sender, state.get_nonce(tx.sender), tx.from_full_shard_key, ), tx.to_full_shard_key, ), value=tx.value, gas_price=tx.gasprice, gas_token_id=tx.gas_token_id, transfer_token_id=tx.transfer_token_id, message_data=tx.data, create_contract=True, gas_remained=remote_gas_reserved, )) success = 1 else: state.delta_token_balance(tx.sender, tx.transfer_token_id, -tx.value) if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP): remote_gas_reserved = tx.startgas - intrinsic_gas ext.add_cross_shard_transaction_deposit( quarkchain.core.CrossShardTransactionDeposit( tx_hash=tx_wrapper_hash, from_address=quarkchain.core.Address( tx.sender, tx.from_full_shard_key), to_address=quarkchain.core.Address(tx.to, tx.to_full_shard_key), value=tx.value, gas_price=tx.gasprice, gas_token_id=tx.gas_token_id, transfer_token_id=tx.transfer_token_id, message_data=tx.data, create_contract=False, gas_remained=remote_gas_reserved, )) success = 1 gas_remained = tx.startgas - local_gas_used - remote_gas_reserved # Refund state.delta_token_balance(message.sender, message.gas_token_id, ext.tx_gasprice * gas_remained) # if x-shard, reserve part of the gas for the target shard miner for fee fee = (tx.gasprice * (local_gas_used - (opcodes.GTXXSHARDCOST if success else 0)) * local_fee_rate.numerator // local_fee_rate.denominator) state.delta_token_balance(state.block_coinbase, tx.gas_token_id, fee) add_dict(state.block_fee_tokens, {message.gas_token_id: fee}) output = [] state.gas_used += local_gas_used if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP): state.gas_used -= opcodes.GTXXSHARDCOST if success else 0 # Construct a receipt r = mk_receipt(state, success, state.logs, contract_address, state.full_shard_key) state.logs = [] state.add_receipt(r) return success, output return apply_transaction_message(state, message, ext, tx.to == b"", intrinsic_gas)
def create_contract(ext, msg): log_msg.debug("CONTRACT CREATION") if msg.is_cross_shard: return 0, msg.gas, b"" if msg.transfer_token_id != ext.default_state_token: # TODODLL calling smart contract with non QKC transfer_token_id is not supported return 0, msg.gas, b"" code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if msg.sender == null_address: msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, 0) # msg.to = sha3(msg.sender + code)[12:] else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = mk_contract_address(msg.sender, msg.to_full_shard_key, nonce) if ext.get_nonce(msg.to) or len(ext.get_code(msg.to)): log_msg.debug("CREATING CONTRACT ON TOP OF EXISTING CONTRACT") return 0, 0, b"" b = ext.get_balances(msg.to) if b != {}: ext.set_balances(msg.to, b) ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b"") # ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug( "CONTRACT CREATION FINISHED", res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat)), ) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576): gas -= gcost else: dat = [] log_msg.debug( "CONTRACT CREATION FAILED", have=gas, want=gcost, block_number=ext.block_number, ) ext.revert(snapshot) return 0, 0, b"" ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug("SETTING CODE", addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat