private void ApplyDaoTransition() { Address withdrawAccount = DaoData.DaoWithdrawalAccount; foreach (Address daoAccount in DaoData.DaoAccounts) { BigInteger balance = _stateProvider.GetBalance(daoAccount); _stateProvider.UpdateBalance(withdrawAccount, balance, Dao.Instance); _stateProvider.UpdateBalance(daoAccount, -balance, Dao.Instance); } }
public TransactionReceipt Execute( Transaction transaction, BlockHeader block) { TransactionTrace trace = null; if (_tracer.IsTracingEnabled) { trace = new TransactionTrace(); } IReleaseSpec spec = _specProvider.GetSpec(block.Number); Address recipient = transaction.To; BigInteger value = transaction.Value; BigInteger gasPrice = transaction.GasPrice; long gasLimit = (long)transaction.GasLimit; byte[] machineCode = transaction.Init; byte[] data = transaction.Data ?? Bytes.Empty; Address sender = transaction.SenderAddress; if (_logger.IsDebugEnabled) { _logger.Debug($"SPEC: {spec.GetType().Name}"); _logger.Debug("HASH: " + transaction.Hash); _logger.Debug("IS_CONTRACT_CREATION: " + transaction.IsContractCreation); _logger.Debug("IS_MESSAGE_CALL: " + transaction.IsMessageCall); _logger.Debug("IS_TRANSFER: " + transaction.IsTransfer); _logger.Debug("SENDER: " + sender); _logger.Debug("TO: " + transaction.To); _logger.Debug("GAS LIMIT: " + transaction.GasLimit); _logger.Debug("GAS PRICE: " + transaction.GasPrice); _logger.Debug("VALUE: " + transaction.Value); _logger.Debug("DATA_LENGTH: " + (transaction.Data?.Length ?? 0)); _logger.Debug("NONCE: " + transaction.Nonce); } if (sender == null) { if (_logger.IsDebugEnabled) { _logger.Debug($"SENDER_NOT_SPECIFIED"); } return(GetNullReceipt(block, 0L)); } long intrinsicGas = _intrinsicGasCalculator.Calculate(transaction, spec); if (_logger.IsDebugEnabled) { _logger.Debug("INTRINSIC GAS: " + intrinsicGas); } if (gasLimit < intrinsicGas) { if (_logger.IsDebugEnabled) { _logger.Debug($"GAS_LIMIT_BELOW_INTRINSIC_GAS {gasLimit} < {intrinsicGas}"); } return(GetNullReceipt(block, 0L)); } if (gasLimit > block.GasLimit - block.GasUsed) { if (_logger.IsDebugEnabled) { _logger.Debug($"BLOCK_GAS_LIMIT_EXCEEDED {gasLimit} > {block.GasLimit} - {block.GasUsed}"); } return(GetNullReceipt(block, 0L)); } if (!_stateProvider.AccountExists(sender)) { if (_logger.IsDebugEnabled) { _logger.Debug($"SENDER_ACCOUNT_DOES_NOT_EXIST {sender}"); } _stateProvider.CreateAccount(sender, 0); } BigInteger senderBalance = _stateProvider.GetBalance(sender); if (intrinsicGas * gasPrice + value > senderBalance) { if (_logger.IsDebugEnabled) { _logger.Debug($"INSUFFICIENT_SENDER_BALANCE: ({sender})b = {senderBalance}"); } return(GetNullReceipt(block, 0L)); } if (transaction.Nonce != _stateProvider.GetNonce(sender)) { if (_logger.IsDebugEnabled) { _logger.Debug($"WRONG_TRANSACTION_NONCE: {transaction.Nonce} (expected {_stateProvider.GetNonce(sender)})"); } return(GetNullReceipt(block, 0L)); } _stateProvider.IncrementNonce(sender); _stateProvider.UpdateBalance(sender, -new BigInteger(gasLimit) * gasPrice, spec); _stateProvider.Commit(spec); long unspentGas = gasLimit - intrinsicGas; long spentGas = gasLimit; List <LogEntry> logEntries = new List <LogEntry>(); if (transaction.IsContractCreation) { Rlp addressBaseRlp = Rlp.Encode( Rlp.Encode(sender), Rlp.Encode(_stateProvider.GetNonce(sender) - 1)); Keccak addressBaseKeccak = Keccak.Compute(addressBaseRlp); recipient = new Address(addressBaseKeccak); } int snapshot = _stateProvider.TakeSnapshot(); int storageSnapshot = _storageProvider.TakeSnapshot(); _stateProvider.UpdateBalance(sender, -value, spec); byte statusCode = StatusCode.Failure; HashSet <Address> destroyedAccounts = new HashSet <Address>(); try { if (transaction.IsContractCreation) { // TODO: review tests around it as it fails on Ropsten 230881 when we throw an exception if (_stateProvider.AccountExists(recipient) && !_stateProvider.IsEmptyAccount(recipient)) { // TODO: review // throw new TransactionCollisionException(); } } if (transaction.IsTransfer) // TODO: this is never called and wrong, to be removed { _stateProvider.UpdateBalance(sender, -value, spec); _stateProvider.UpdateBalance(recipient, value, spec); statusCode = StatusCode.Success; } else { bool isPrecompile = recipient.IsPrecompiled(spec); ExecutionEnvironment env = new ExecutionEnvironment(); env.Value = value; env.TransferValue = value; env.Sender = sender; env.ExecutingAccount = recipient; env.CurrentBlock = block; env.GasPrice = gasPrice; env.InputData = data ?? new byte[0]; env.CodeInfo = isPrecompile ? new CodeInfo(recipient) : machineCode == null?_virtualMachine.GetCachedCodeInfo(recipient) : new CodeInfo(machineCode); env.Originator = sender; ExecutionType executionType = isPrecompile ? ExecutionType.DirectPrecompile : transaction.IsContractCreation ? ExecutionType.DirectCreate : ExecutionType.Transaction; TransactionSubstate substate; byte[] output; using (EvmState state = new EvmState(unspentGas, env, executionType, false)) { (output, substate) = _virtualMachine.Run(state, spec, trace); unspentGas = state.GasAvailable; } if (substate.ShouldRevert) { if (_logger.IsDebugEnabled) { _logger.Debug("REVERTING"); } logEntries.Clear(); destroyedAccounts.Clear(); _stateProvider.Restore(snapshot); _storageProvider.Restore(storageSnapshot); } else { if (transaction.IsContractCreation) { long codeDepositGasCost = output.Length * GasCostOf.CodeDeposit; if (spec.IsEip170Enabled && output.Length > 0x6000) { codeDepositGasCost = long.MaxValue; } if (unspentGas < codeDepositGasCost && spec.IsEip2Enabled) { throw new OutOfGasException(); } if (unspentGas >= codeDepositGasCost) { Keccak codeHash = _stateProvider.UpdateCode(output); _stateProvider.UpdateCodeHash(recipient, codeHash, spec); unspentGas -= codeDepositGasCost; } } logEntries.AddRange(substate.Logs); foreach (Address toBeDestroyed in substate.DestroyList) { destroyedAccounts.Add(toBeDestroyed); } statusCode = StatusCode.Success; } spentGas = Refund(gasLimit, unspentGas, substate, sender, gasPrice, spec); } } catch (Exception ex) when(ex is EvmException || ex is OverflowException) // TODO: OverflowException? still needed? hope not { if (_logger.IsDebugEnabled) { _logger.Debug($"EVM EXCEPTION: {ex.GetType().Name}"); } logEntries.Clear(); destroyedAccounts.Clear(); _stateProvider.Restore(snapshot); _storageProvider.Restore(storageSnapshot); } foreach (Address toBeDestroyed in destroyedAccounts) { if (_logger.IsDebugEnabled) { _logger.Debug($"DESTROYING: {toBeDestroyed}"); } _stateProvider.DeleteAccount(toBeDestroyed); } if (_logger.IsDebugEnabled) { _logger.Debug("GAS SPENT: " + spentGas); } if (!destroyedAccounts.Contains(block.Beneficiary)) { if (!_stateProvider.AccountExists(block.Beneficiary)) { _stateProvider.CreateAccount(block.Beneficiary, spentGas * gasPrice); } else { _stateProvider.UpdateBalance(block.Beneficiary, spentGas * gasPrice, spec); } } _storageProvider.Commit(spec); _stateProvider.Commit(spec); block.GasUsed += spentGas; if (_tracer.IsTracingEnabled) { trace.Gas = spentGas; _tracer.SaveTrace(Transaction.CalculateHash(transaction), trace); } return(BuildTransactionReceipt(statusCode, logEntries.Any() ? logEntries.ToArray() : LogEntry.EmptyLogs, block.GasUsed, recipient)); }