Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *co
txContext := NewCVMTxContext(msg)
vm := vm.NewCVM(context, txContext, statedb, config, cfg)

_, _, _, _, err = ApplyMessage(vm, msg, gaspool, quotaPool)
_, err = ApplyMessage(vm, msg, gaspool, quotaPool)
return err
}
16 changes: 8 additions & 8 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, qp
// Update the evm with the new transaction context.
cvm.Reset(txContext, statedb)
// Apply the transaction to the current state (included in the env)
_, gas, quota, failed, err := ApplyMessage(cvm, msg, gp, qp)
result, err := ApplyMessage(cvm, msg, gp, qp)
if err != nil {
return nil, 0, err
}

if quota > 0 {
header.QuotaUsed += quota
if result.Quota > 0 {
header.QuotaUsed += result.Quota

if header.Quota < header.QuotaUsed {
header.QuotaUsed -= quota
header.QuotaUsed -= result.Quota
return nil, 0, ErrQuotaLimitReached //errors.New("quota")
}
}
Expand All @@ -134,13 +134,13 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, qp
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}

*usedGas += gas
*usedGas += result.UsedGas

// Create a new receipt for the transaction, storing the intermediate root and gas used
// by the tx.
receipt := types.NewReceipt(root, failed, *usedGas)
receipt := types.NewReceipt(root, result.Failed(), *usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = gas
receipt.GasUsed = result.UsedGas
// if the transaction created a contract, store the creation address in the receipt.
if msg.To == nil {
receipt.ContractAddress = crypto.CreateAddress(cvm.TxContext.Origin, tx.Nonce())
Expand All @@ -152,7 +152,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, qp
receipt.BlockNumber = blockNumber
receipt.TransactionIndex = uint(statedb.TxIndex())

return receipt, gas, err
return receipt, result.UsedGas, err
}

// ApplyTransaction attempts to apply a transaction to the given state database
Expand Down
81 changes: 64 additions & 17 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,43 @@ import (
torrentfs "github.com/CortexFoundation/torrentfs/types"
)

// ExecutionResult includes all output after executing given evm
// message no matter the execution itself is successful or not.
type ExecutionResult struct {
UsedGas uint64 // Total used gas, not including the refunded gas
Quota uint64
RefundedGas uint64 // Total gas refunded after execution
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
}

// Unwrap returns the internal evm error which allows us for further
// analysis outside.
func (result *ExecutionResult) Unwrap() error {
return result.Err
}

// Failed returns the indicator whether the execution is successful or not
func (result *ExecutionResult) Failed() bool { return result.Err != nil }

// Return is a helper function to help caller distinguish between revert reason
// and function return. Return returns the data after execution if no error occurs.
func (result *ExecutionResult) Return() []byte {
if result.Err != nil {
return nil
}
return common.CopyBytes(result.ReturnData)
}

// Revert returns the concrete revert reason if the execution is aborted by `REVERT`
// opcode. Note the reason can be nil if no data supplied with revert opcode.
func (result *ExecutionResult) Revert() []byte {
if result.Err != vm.ErrExecutionReverted {
return nil
}
return common.CopyBytes(result.ReturnData)
}

var (
errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas")
//PER_UPLOAD_BYTES uint64 = 10 * 512 * 1024
Expand Down Expand Up @@ -161,7 +198,7 @@ func NewStateTransition(cvm *vm.CVM, msg *Message, gp *GasPool, qp *QuotaPool) *
// 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(cvm *vm.CVM, msg *Message, gp *GasPool, qp *QuotaPool) ([]byte, uint64, uint64, bool, error) {
func ApplyMessage(cvm *vm.CVM, msg *Message, gp *GasPool, qp *QuotaPool) (*ExecutionResult, error) {
return NewStateTransition(cvm, msg, gp, qp).TransitionDb()
}

Expand Down Expand Up @@ -295,9 +332,9 @@ func (st *StateTransition) TorrentSync(meta common.Address, dir string, errCh ch
// 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, quotaUsed 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 nil, err
}

msg := st.msg
Expand All @@ -316,27 +353,28 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed
// Pay intrinsic gas
gas, err := IntrinsicGas(msg.Data, contractCreation, st.uploading(), homestead, istanbul)
if err != nil {
return nil, 0, 0, false, err
return nil, err
}
if st.gas < gas {
return nil, 0, 0, false, fmt.Errorf("%w: have %d, want %d", vm.ErrOutOfGas, st.gas, gas)
return nil, fmt.Errorf("%w: have %d, want %d", vm.ErrOutOfGas, st.gas, gas)
}
st.gas -= gas

if msg.Value.Sign() > 0 && !st.cvm.Context.CanTransfer(st.state, msg.From, msg.Value) {
return nil, 0, 0, false, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
}

if blocked, num := security.IsBlocked(msg.From); blocked && st.cvm.Context.BlockNumber.Cmp(big.NewInt(num)) >= 0 {
log.Debug("Bad address encounter!!", "addr", msg.From, "number", num)
return nil, 0, 0, false, fmt.Errorf("%w: address %v", errors.New("Bad address encounter"), msg.From.Hex())
return nil, fmt.Errorf("%w: address %v", errors.New("Bad address encounter"), msg.From.Hex())
}

var (
cvm = st.cvm
// vm errors do not effect consensus and are therefor
// not assigned to err, except for insufficient balance
// error.
ret []byte
vmerr error
)
if contractCreation {
Expand All @@ -352,7 +390,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed

if vmerr != nil {
if vmerr == vm.ErrRuntime {
return nil, 0, 0, false, vmerr
return nil, vmerr
}

log.Debug("VM returned with error", "err", vmerr, "number", cvm.Context.BlockNumber, "from", msg.From.Hex())
Expand All @@ -361,7 +399,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed
// sufficient balance to make the transfer happen. The first
// balance transfer may never fail.
if vmerr == vm.ErrInsufficientBalance {
return nil, 0, 0, false, vmerr
return nil, vmerr
}

//if vmerr == vm.ErrMetaInfoNotMature {
Expand All @@ -371,7 +409,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed

//gas cost below this line

st.refundGas()
var gasRefund uint64
gasRefund = st.refundGas()
//model gas
gu := st.gasUsed()
//if (vmerr == nil || vmerr == vm.ErrOutOfGas) && st.modelGas != nil && len(st.modelGas) > 0 { //pay ctx to the model authors by the model gas * current price
Expand All @@ -382,7 +421,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed
}

if gu < mgas {
return nil, 0, 0, false, vm.ErrInsufficientBalance
return nil, vm.ErrInsufficientBalance
}

gu -= mgas
Expand Down Expand Up @@ -431,31 +470,37 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, quotaUsed
request = inputMeta.RawSize - remain
}
} else {
return nil, 0, 0, false, vm.ErrRuntime
return nil, vm.ErrRuntime
}

if err != nil {
return nil, 0, 0, false, vm.ErrRuntime
return nil, vm.ErrRuntime
}
info := common.StorageEntry{
Hash: ih,
Size: request,
}
if err = synapse.Engine().Download(info); err != nil {
return nil, 0, 0, false, err
return nil, err
}
}
}

return ret, st.gasUsed(), quota, vmerr != nil, err
return &ExecutionResult{
UsedGas: st.gasUsed(),
Quota: quota,
RefundedGas: gasRefund,
Err: vmerr,
ReturnData: ret,
}, err
}

// vote to model
func (st *StateTransition) uploading() bool {
return st.msg != nil && st.msg.To != nil && st.msg.Value.Sign() == 0 && st.state.Uploading(st.to()) // && st.gas >= params.UploadGas
}

func (st *StateTransition) refundGas() {
func (st *StateTransition) refundGas() uint64 {
// Apply refund counter, capped to half of the used gas.
refund := st.gasUsed() / 2
if refund > st.state.GetRefund() {
Expand All @@ -470,6 +515,8 @@ func (st *StateTransition) refundGas() {
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
st.gp.AddGas(st.gas)

return refund
}

// gasUsed returns the amount of gas used up by the state transition.
Expand Down
2 changes: 1 addition & 1 deletion ctxc/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewCVM(context, txContext, statedb, api.config, vm.Config{})
if _, _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), new(core.QuotaPool).AddQuota(math.MaxUint64)); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), new(core.QuotaPool).AddQuota(math.MaxUint64)); err != nil {
return nil, vm.BlockContext{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down
2 changes: 1 addition & 1 deletion ctxc/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func (ctxc *Cortex) stateAtTransaction(block *types.Block, txIndex int, reexec u
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewCVM(context, txContext, statedb, ctxc.blockchain.Config(), vm.Config{})
statedb.SetTxContext(tx.Hash(), idx)
if _, _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down
8 changes: 4 additions & 4 deletions ctxc/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmenv = vm.NewCVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
)
statedb.SetTxContext(tx.Hash(), i)
if _, _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not
// return the roots. Most likely, the caller already knows that a certain transaction fails to
Expand Down Expand Up @@ -661,7 +661,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
msg, _ := core.TransactionToMessage(tx, signer)
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewCVM(blockCtx, core.NewCVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota())); err != nil {
failed = err
break
}
Expand Down Expand Up @@ -772,7 +772,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Execute the transaction and flush any traces to disk
vmenv := vm.NewCVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.SetTxContext(tx.Hash(), i)
_, _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota()))
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), new(core.QuotaPool).AddQuota(block.Quota()))
if writer != nil {
writer.Flush()
}
Expand Down Expand Up @@ -945,7 +945,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
// Run the transaction with tracing enabled.
// Call Prepare to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
if _, _, _, _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit), new(core.QuotaPool).AddQuota(vmctx.Quota)); err != nil {
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit), new(core.QuotaPool).AddQuota(vmctx.Quota)); err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
}
return tracer.GetResult()
Expand Down
8 changes: 4 additions & 4 deletions internal/ctxcapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,8 @@ func (s *PublicBlockChainAPI) GetSolidityBytes(ctx context.Context, address comm
header := block.Header()
msg, err := core.TransactionToMessage(tx, types.MakeSigner(s.b.ChainConfig(), block.Number(), block.Time()))
cvm := s.b.GetCVM(ctx, msg, state, header, vm.Config{})
_, _, _, failed, err := core.ApplyMessage(cvm, msg, gp, qp)
if err != nil || failed {
result, err := core.ApplyMessage(cvm, msg, gp, qp)
if err != nil || result.Failed() {
return nil, err
}
state.Finalise(true)
Expand Down Expand Up @@ -911,7 +911,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
qp := new(core.QuotaPool).AddQuota(math.MaxUint64)
res, gas, _, failed, err := core.ApplyMessage(cvm, msg, gp, qp)
result, err := core.ApplyMessage(cvm, msg, gp, qp)
if err := state.Error(); err != nil {
return nil, 0, false, err
}
Expand All @@ -921,7 +921,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}

return res, gas, failed, err
return result.Return(), result.UsedGas, result.Failed(), err
}

// Call executes the given transaction on the state for the given block number.
Expand Down