mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
core/vm: added RunWithContext to the EVM for cancellation
Implemented RunWithContext which allows the execution of the EVM to be halted mid-flight. This is useful when using the EVM unmetered or when using the Light Client, which requires control over the EVM run loop.
This commit is contained in:
parent
c7b5c92524
commit
243c66833b
1 changed files with 24 additions and 1 deletions
|
|
@ -17,8 +17,10 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -54,6 +56,10 @@ type EVM struct {
|
||||||
jumpTable vmJumpTable
|
jumpTable vmJumpTable
|
||||||
cfg Config
|
cfg Config
|
||||||
gasTable params.GasTable
|
gasTable params.GasTable
|
||||||
|
|
||||||
|
// done is an atomic int and is used for
|
||||||
|
// cancellation during RunWithContext.
|
||||||
|
done int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new instance of the EVM.
|
// New returns a new instance of the EVM.
|
||||||
|
|
@ -66,6 +72,18 @@ func New(env *Environment, cfg Config) *EVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunWithContext allows the EVM to be ran with a cancellation method by passing in a context.Context. The EVM
|
||||||
|
// behaves exactly the same as an EVM without a context.
|
||||||
|
//
|
||||||
|
// RunWithContext is only used for the initial call and shouldn't be called more than once.
|
||||||
|
func (evm *EVM) RunWithContext(ctx context.Context, contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
atomic.StoreInt32(&evm.done, 1)
|
||||||
|
}()
|
||||||
|
return evm.Run(contract, input)
|
||||||
|
}
|
||||||
|
|
||||||
// Run loops and evaluates the contract's code with the given input data
|
// Run loops and evaluates the contract's code with the given input data
|
||||||
func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
evm.env.Depth++
|
evm.env.Depth++
|
||||||
|
|
@ -113,7 +131,11 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
// The EVM main run loop (contextual). This loop runs until either an
|
||||||
|
// explicit STOP, RETURN or SUICIDE is executed, an error accured during
|
||||||
|
// the execution of one of the operations or until the evm.done is set by
|
||||||
|
// the parent context.Context.
|
||||||
|
for atomic.LoadInt32(&evm.done) == 0 {
|
||||||
// Get the memory location of pc
|
// Get the memory location of pc
|
||||||
op = contract.GetOp(pc)
|
op = contract.GetOp(pc)
|
||||||
|
|
||||||
|
|
@ -166,6 +188,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue