|
|
|
@ -22,15 +22,14 @@ import ( |
|
|
|
|
"math/big" |
|
|
|
|
"sort" |
|
|
|
|
|
|
|
|
|
staking2 "github.com/harmony-one/harmony/staking" |
|
|
|
|
"github.com/harmony-one/harmony/staking/network" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/ethereum/go-ethereum/rlp" |
|
|
|
|
"github.com/harmony-one/harmony/core/types" |
|
|
|
|
"github.com/harmony-one/harmony/core/vm" |
|
|
|
|
"github.com/harmony-one/harmony/internal/params" |
|
|
|
|
"github.com/harmony-one/harmony/internal/utils" |
|
|
|
|
staking2 "github.com/harmony-one/harmony/staking" |
|
|
|
|
"github.com/harmony-one/harmony/staking/network" |
|
|
|
|
staking "github.com/harmony-one/harmony/staking/types" |
|
|
|
|
"github.com/pkg/errors" |
|
|
|
|
) |
|
|
|
@ -97,6 +96,13 @@ type Message interface { |
|
|
|
|
BlockNum() *big.Int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ExecutionResult is the return value from a transaction committed to the DB
|
|
|
|
|
type ExecutionResult struct { |
|
|
|
|
ReturnData []byte |
|
|
|
|
UsedGas uint64 |
|
|
|
|
VMErr error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
|
|
|
|
|
func IntrinsicGas(data []byte, contractCreation, homestead, istanbul, isValidatorCreation bool) (uint64, error) { |
|
|
|
|
// Set the starting gas for the raw transaction
|
|
|
|
@ -157,7 +163,7 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool, bc ChainContext) |
|
|
|
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
|
|
|
|
// indicates a core error meaning that the message would always fail for that particular
|
|
|
|
|
// state and would never be accepted within a block.
|
|
|
|
|
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { |
|
|
|
|
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (ExecutionResult, error) { |
|
|
|
|
return NewStateTransition(evm, msg, gp, nil).TransitionDb() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -218,9 +224,9 @@ func (st *StateTransition) preCheck() error { |
|
|
|
|
// TransitionDb will transition the state by applying the current message and
|
|
|
|
|
// returning the result including the used gas. It returns an error if failed.
|
|
|
|
|
// An error indicates a consensus issue.
|
|
|
|
|
func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) { |
|
|
|
|
if err = st.preCheck(); err != nil { |
|
|
|
|
return |
|
|
|
|
func (st *StateTransition) TransitionDb() (ExecutionResult, error) { |
|
|
|
|
if err := st.preCheck(); err != nil { |
|
|
|
|
return ExecutionResult{}, err |
|
|
|
|
} |
|
|
|
|
msg := st.msg |
|
|
|
|
sender := vm.AccountRef(msg.From()) |
|
|
|
@ -231,34 +237,33 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo |
|
|
|
|
// Pay intrinsic gas
|
|
|
|
|
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul, false) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, 0, false, err |
|
|
|
|
return ExecutionResult{}, err |
|
|
|
|
} |
|
|
|
|
if err = st.useGas(gas); err != nil { |
|
|
|
|
return nil, 0, false, err |
|
|
|
|
return ExecutionResult{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
evm = st.evm |
|
|
|
|
// vm errors do not effect consensus and are therefor
|
|
|
|
|
// not assigned to err, except for insufficient balance
|
|
|
|
|
// error.
|
|
|
|
|
vmerr error |
|
|
|
|
) |
|
|
|
|
evm := st.evm |
|
|
|
|
|
|
|
|
|
var ret []byte |
|
|
|
|
// All VM errors are valid except for insufficient balance, therefore returned separately
|
|
|
|
|
var vmErr error |
|
|
|
|
|
|
|
|
|
if contractCreation { |
|
|
|
|
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) |
|
|
|
|
ret, _, st.gas, vmErr = evm.Create(sender, st.data, st.gas, st.value) |
|
|
|
|
} else { |
|
|
|
|
// Increment the nonce for the next transaction
|
|
|
|
|
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) |
|
|
|
|
ret, st.gas, vmerr = evm.Call(sender, st.to(), st.data, st.gas, st.value) |
|
|
|
|
ret, st.gas, vmErr = evm.Call(sender, st.to(), st.data, st.gas, st.value) |
|
|
|
|
} |
|
|
|
|
if vmerr != nil { |
|
|
|
|
utils.Logger().Info().Err(vmerr).Msg("VM returned with error") |
|
|
|
|
if vmErr != nil { |
|
|
|
|
utils.Logger().Info().Err(vmErr).Msg("VM returned with error") |
|
|
|
|
// The only possible consensus-error would be if there wasn't
|
|
|
|
|
// sufficient balance to make the transfer happen. The first
|
|
|
|
|
// balance transfer may never fail.
|
|
|
|
|
|
|
|
|
|
if vmerr == vm.ErrInsufficientBalance { |
|
|
|
|
return nil, 0, false, vmerr |
|
|
|
|
if vmErr == vm.ErrInsufficientBalance { |
|
|
|
|
return ExecutionResult{}, vmErr |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
st.refundGas() |
|
|
|
@ -269,7 +274,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo |
|
|
|
|
st.state.AddBalance(st.evm.Coinbase, txFee) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ret, st.gasUsed(), vmerr != nil, err |
|
|
|
|
return ExecutionResult{ |
|
|
|
|
ReturnData: ret, |
|
|
|
|
UsedGas: st.gasUsed(), |
|
|
|
|
VMErr: vmErr, |
|
|
|
|
}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (st *StateTransition) refundGas() { |
|
|
|
|