Skip to content

Commit

Permalink
Merge pull request #58 from qianbin/runtime
Browse files Browse the repository at this point in the history
feat(runtime): add runtime.PrepareClause to allow interrupt clause ex…
  • Loading branch information
libotony authored Jul 2, 2018
2 parents 6781577 + 3518371 commit 76a1a71
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 20 deletions.
65 changes: 45 additions & 20 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package runtime

import (
"math/big"
"sync/atomic"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -238,31 +239,55 @@ func (rt *Runtime) ExecuteClause(
gas uint64,
txCtx *xenv.TransactionContext,
) *Output {
exec, _ := rt.PrepareClause(clause, clauseIndex, gas, txCtx)
output, _ := exec()
return output
}

// PrepareClause prepare to execute clause.
// It allows to interrupt execution.
func (rt *Runtime) PrepareClause(
clause *tx.Clause,
clauseIndex uint32,
gas uint64,
txCtx *xenv.TransactionContext,
) (exec func() (output *Output, interrupted bool), interrupt func()) {
var (
stateDB = statedb.New(rt.state)
evm = rt.newEVM(stateDB, clauseIndex, txCtx)
data []byte
leftOverGas uint64
vmErr error
contractAddr *thor.Address
stateDB = statedb.New(rt.state)
evm = rt.newEVM(stateDB, clauseIndex, txCtx)
data []byte
leftOverGas uint64
vmErr error
contractAddr *thor.Address
interruptFlag uint32
)
if clause.To() == nil {
var caddr common.Address
data, caddr, leftOverGas, vmErr = evm.Create(vm.AccountRef(txCtx.Origin), clause.Data(), gas, clause.Value())
contractAddr = (*thor.Address)(&caddr)
} else {
data, leftOverGas, vmErr = evm.Call(vm.AccountRef(txCtx.Origin), common.Address(*clause.To()), clause.Data(), gas, clause.Value())

exec = func() (*Output, bool) {
if clause.To() == nil {
var caddr common.Address
data, caddr, leftOverGas, vmErr = evm.Create(vm.AccountRef(txCtx.Origin), clause.Data(), gas, clause.Value())
contractAddr = (*thor.Address)(&caddr)
} else {
data, leftOverGas, vmErr = evm.Call(vm.AccountRef(txCtx.Origin), common.Address(*clause.To()), clause.Data(), gas, clause.Value())
}

interrupted := atomic.LoadUint32(&interruptFlag) != 0
output := &Output{
Data: data,
LeftOverGas: leftOverGas,
RefundGas: stateDB.GetRefund(),
VMErr: vmErr,
ContractAddress: contractAddr,
}
output.Events, output.Transfers = stateDB.GetLogs()
return output, interrupted
}

output := &Output{
Data: data,
LeftOverGas: leftOverGas,
RefundGas: stateDB.GetRefund(),
VMErr: vmErr,
ContractAddress: contractAddr,
interrupt = func() {
atomic.StoreUint32(&interruptFlag, 1)
evm.Cancel()
}
output.Events, output.Transfers = stateDB.GetLogs()
return output
return
}

// ExecuteTransaction executes a transaction.
Expand Down
17 changes: 17 additions & 0 deletions runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,23 @@ func TestCall(t *testing.T) {
}

assert.Equal(t, thor.Address(addr), genesis.DevAccounts()[0].Address)

// contract NeverStop {
// constructor() public {
// while(true) {
// }
// }
// }
data, _ = hex.DecodeString("6080604052348015600f57600080fd5b505b600115601b576011565b60358060286000396000f3006080604052600080fd00a165627a7a7230582026c386600e61384b3a93bf45760f3207b5cac072cec31c9cea1bc7099bda49b00029")
exec, interrupt := rt.PrepareClause(tx.NewClause(nil).WithData(data), 0, math.MaxUint64, &xenv.TransactionContext{})

go func() {
interrupt()
}()

out, interrupted := exec()
assert.NotNil(t, out)
assert.True(t, interrupted)
}

func TestExecuteTransaction(t *testing.T) {
Expand Down

0 comments on commit 76a1a71

Please sign in to comment.