mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 13:16:42 +00:00
patch (#3)
* Add verifier for controlling contract method whether can be called. * change code name Co-authored-by: BananaLF <864685021@qq.com>
This commit is contained in:
parent
26675454bf
commit
034b2bf6ad
16 changed files with 1411 additions and 5 deletions
233
contractverifier/contract_verifier_test.go
Normal file
233
contractverifier/contract_verifier_test.go
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
package contractverifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UNKNOWN = iota
|
||||||
|
SELFDESTRUCT
|
||||||
|
NORMAL_CALL
|
||||||
|
)
|
||||||
|
|
||||||
|
type contractVerifierTest struct {
|
||||||
|
verifiers []verifierTest
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContractVerifier() *contractVerifierTest {
|
||||||
|
return &contractVerifierTest{verifiers: make([]verifierTest, 0)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type verifierTest struct {
|
||||||
|
VerifierType int
|
||||||
|
Op vm.OpCode
|
||||||
|
From common.Address
|
||||||
|
To common.Address
|
||||||
|
Input string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVerifierTest(verifierType int, op vm.OpCode, from, to common.Address, input []byte, value *big.Int) verifierTest {
|
||||||
|
return verifierTest{
|
||||||
|
VerifierType: verifierType,
|
||||||
|
Op: op,
|
||||||
|
From: from,
|
||||||
|
To: to,
|
||||||
|
Input: hexutil.Encode(input),
|
||||||
|
Value: fmt.Sprintf("0x%s", value.Text(16)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cv *contractVerifierTest) Verify(stateDB vm.StateDB, op vm.OpCode, from, to common.Address, input []byte, value *big.Int) error {
|
||||||
|
verifierTest := NewVerifierTest(UNKNOWN, op, from, to, input, value)
|
||||||
|
if op == vm.SELFDESTRUCT {
|
||||||
|
verifierTest.VerifierType = SELFDESTRUCT
|
||||||
|
} else if op == vm.CALL || op == vm.DELEGATECALL || op == vm.STATICCALL || op == vm.CALLCODE {
|
||||||
|
verifierTest.VerifierType = NORMAL_CALL
|
||||||
|
}
|
||||||
|
cv.verifiers = append(cv.verifiers, verifierTest)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertVerifierType(op vm.OpCode) int {
|
||||||
|
result := UNKNOWN
|
||||||
|
if op == vm.SELFDESTRUCT {
|
||||||
|
result = SELFDESTRUCT
|
||||||
|
} else if op == vm.CALL || op == vm.DELEGATECALL || op == vm.STATICCALL || op == vm.CALLCODE {
|
||||||
|
result = NORMAL_CALL
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// callTrace is the result of a callTracer run.
|
||||||
|
type callTrace struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
From common.Address `json:"from"`
|
||||||
|
To common.Address `json:"to"`
|
||||||
|
Input hexutil.Bytes `json:"input"`
|
||||||
|
Output hexutil.Bytes `json:"output"`
|
||||||
|
Gas *hexutil.Uint64 `json:"gas,omitempty"`
|
||||||
|
GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"`
|
||||||
|
Value *hexutil.Big `json:"value,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Calls []callTrace `json:"calls,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *callTrace) GetArrayCall() []verifierTest {
|
||||||
|
results := make([]verifierTest, 0)
|
||||||
|
self := NewVerifierTest(convertVerifierType(vm.StringToOp(ct.Type)), vm.StringToOp(ct.Type), ct.From, ct.To, nil, nil)
|
||||||
|
self.Input = ct.Input.String()
|
||||||
|
self.Value = ct.Value.String()
|
||||||
|
results = append(results, self)
|
||||||
|
|
||||||
|
callsNumber := len(ct.Calls)
|
||||||
|
if callsNumber == 0 {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, _ := range ct.Calls {
|
||||||
|
nextResults := ct.Calls[i].GetArrayCall()
|
||||||
|
results = append(results, nextResults...)
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
type callContext struct {
|
||||||
|
Number math.HexOrDecimal64 `json:"number"`
|
||||||
|
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
|
||||||
|
Time math.HexOrDecimal64 `json:"timestamp"`
|
||||||
|
GasLimit math.HexOrDecimal64 `json:"gasLimit"`
|
||||||
|
Miner common.Address `json:"miner"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// callTracerTest defines a single test to check the call tracer against.
|
||||||
|
type callTracerTest struct {
|
||||||
|
Genesis *core.Genesis `json:"genesis"`
|
||||||
|
Context *callContext `json:"context"`
|
||||||
|
Input string `json:"input"`
|
||||||
|
Result *callTrace `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct callTracerTest) GetArrayResult() []verifierTest {
|
||||||
|
return ct.Result.GetArrayCall()
|
||||||
|
}
|
||||||
|
|
||||||
|
// camel converts a snake cased input string into a camel cased output.
|
||||||
|
func camel(str string) string {
|
||||||
|
pieces := strings.Split(str, "_")
|
||||||
|
for i := 1; i < len(pieces); i++ {
|
||||||
|
pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:]
|
||||||
|
}
|
||||||
|
return strings.Join(pieces, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) {
|
||||||
|
sdb := state.NewDatabase(db)
|
||||||
|
statedb, _ := state.New(common.Hash{}, sdb, nil)
|
||||||
|
for addr, a := range accounts {
|
||||||
|
statedb.SetCode(addr, a.Code)
|
||||||
|
statedb.SetNonce(addr, a.Nonce)
|
||||||
|
statedb.SetBalance(addr, a.Balance)
|
||||||
|
for k, v := range a.Storage {
|
||||||
|
statedb.SetState(addr, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Commit and re-open to start with a clean state.
|
||||||
|
root, _ := statedb.Commit(false)
|
||||||
|
|
||||||
|
var snaps *snapshot.Tree
|
||||||
|
if snapshotter {
|
||||||
|
snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, root, false, true, false)
|
||||||
|
}
|
||||||
|
statedb, _ = state.New(root, sdb, snaps)
|
||||||
|
return snaps, statedb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterates over all the input-output datasets in the tracer test harness and
|
||||||
|
// runs the JavaScript tracers against them.
|
||||||
|
func TestOKVerify(t *testing.T) {
|
||||||
|
files, err := ioutil.ReadDir("testdata")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to retrieve tracer test suite: %v", err)
|
||||||
|
}
|
||||||
|
//index := 0
|
||||||
|
for _, file := range files {
|
||||||
|
//if i < index {
|
||||||
|
// continue
|
||||||
|
//} else if i > index {
|
||||||
|
// return
|
||||||
|
//} else {
|
||||||
|
// fmt.Println("@@@@@@@@@@@@@@@@@@@@", file.Name())
|
||||||
|
//}
|
||||||
|
file := file // capture range variable
|
||||||
|
t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Call tracer test found, read if from disk
|
||||||
|
blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read testcase: %v", err)
|
||||||
|
}
|
||||||
|
test := new(callTracerTest)
|
||||||
|
if err := json.Unmarshal(blob, test); err != nil {
|
||||||
|
t.Fatalf("failed to parse testcase: %v", err)
|
||||||
|
}
|
||||||
|
// Configure a blockchain with the given prestate
|
||||||
|
tx := new(types.Transaction)
|
||||||
|
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
|
||||||
|
t.Fatalf("failed to parse testcase input: %v", err)
|
||||||
|
}
|
||||||
|
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||||
|
origin, _ := signer.Sender(tx)
|
||||||
|
txContext := vm.TxContext{
|
||||||
|
Origin: origin,
|
||||||
|
GasPrice: tx.GasPrice(),
|
||||||
|
}
|
||||||
|
context := vm.BlockContext{
|
||||||
|
CanTransfer: core.CanTransfer,
|
||||||
|
Transfer: core.Transfer,
|
||||||
|
Coinbase: test.Context.Miner,
|
||||||
|
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
|
||||||
|
Time: new(big.Int).SetUint64(uint64(test.Context.Time)),
|
||||||
|
Difficulty: (*big.Int)(test.Context.Difficulty),
|
||||||
|
GasLimit: uint64(test.Context.GasLimit),
|
||||||
|
}
|
||||||
|
_, statedb := makePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
|
||||||
|
|
||||||
|
verifierTest := NewContractVerifier()
|
||||||
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{ContractVerifier: verifierTest})
|
||||||
|
|
||||||
|
msg, err := tx.AsMessage(signer, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
|
}
|
||||||
|
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
|
if _, err = st.TransitionDb(); err != nil {
|
||||||
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
|
}
|
||||||
|
actual := verifierTest.verifiers
|
||||||
|
excepted := test.GetArrayResult()
|
||||||
|
require.Equal(t, excepted, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
415
contractverifier/testdata/deep_calls.json
vendored
Normal file
415
contractverifier/testdata/deep_calls.json
vendored
Normal file
File diff suppressed because one or more lines are too long
98
contractverifier/testdata/delegatecall.json
vendored
Normal file
98
contractverifier/testdata/delegatecall.json
vendored
Normal file
File diff suppressed because one or more lines are too long
66
contractverifier/testdata/inner_create_oog_outer_throw.json
vendored
Normal file
66
contractverifier/testdata/inner_create_oog_outer_throw.json
vendored
Normal file
File diff suppressed because one or more lines are too long
63
contractverifier/testdata/inner_instafail.json
vendored
Normal file
63
contractverifier/testdata/inner_instafail.json
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"genesis": {
|
||||||
|
"difficulty": "117067574",
|
||||||
|
"extraData": "0xd783010502846765746887676f312e372e33856c696e7578",
|
||||||
|
"gasLimit": "4712380",
|
||||||
|
"hash": "0xe05db05eeb3f288041ecb10a787df121c0ed69499355716e17c307de313a4486",
|
||||||
|
"miner": "0x0c062b329265c965deef1eede55183b3acb8f611",
|
||||||
|
"mixHash": "0xb669ae39118a53d2c65fd3b1e1d3850dd3f8c6842030698ed846a2762d68b61d",
|
||||||
|
"nonce": "0x2b469722b8e28c45",
|
||||||
|
"number": "24973",
|
||||||
|
"stateRoot": "0x532a5c3f75453a696428db078e32ae283c85cb97e4d8560dbdf022adac6df369",
|
||||||
|
"timestamp": "1479891145",
|
||||||
|
"totalDifficulty": "1892250259406",
|
||||||
|
"alloc": {
|
||||||
|
"0x6c06b16512b332e6cd8293a2974872674716ce18": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"nonce": "1",
|
||||||
|
"code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e1a7d4d146036575b6000565b34600057604e60048080359060200190919050506050565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f19350505050505b5056",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"0x66fdfd05e46126a07465ad24e40cc0597bc1ef31": {
|
||||||
|
"balance": "0x229ebbb36c3e0f20",
|
||||||
|
"nonce": "3",
|
||||||
|
"code": "0x",
|
||||||
|
"storage": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"chainId": 3,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"daoForkSupport": true,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
|
||||||
|
"eip155Block": 10,
|
||||||
|
"eip158Block": 10,
|
||||||
|
"byzantiumBlock": 1700000,
|
||||||
|
"constantinopleBlock": 4230000,
|
||||||
|
"petersburgBlock": 4939394,
|
||||||
|
"istanbulBlock": 6485846,
|
||||||
|
"muirGlacierBlock": 7117117,
|
||||||
|
"ethash": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"number": "24974",
|
||||||
|
"difficulty": "117067574",
|
||||||
|
"timestamp": "1479891162",
|
||||||
|
"gasLimit": "4712388",
|
||||||
|
"miner": "0xc822ef32e6d26e170b70cf761e204c1806265914"
|
||||||
|
},
|
||||||
|
"input": "0xf889038504a81557008301f97e946c06b16512b332e6cd8293a2974872674716ce1880a42e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b1600002aa0e2a6558040c5d72bc59f2fb62a38993a314c849cd22fb393018d2c5af3112095a01bdb6d7ba32263ccc2ecc880d38c49d9f0c5a72d8b7908e3122b31356d349745",
|
||||||
|
"result": {
|
||||||
|
"type": "CALL",
|
||||||
|
"from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31",
|
||||||
|
"to": "0x6c06b16512b332e6cd8293a2974872674716ce18",
|
||||||
|
"value": "0x0",
|
||||||
|
"gas": "0x1a466",
|
||||||
|
"gasUsed": "0x1dc6",
|
||||||
|
"input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000",
|
||||||
|
"output": "0x",
|
||||||
|
"calls": []
|
||||||
|
}
|
||||||
|
}
|
||||||
81
contractverifier/testdata/inner_throw_outer_revert.json
vendored
Normal file
81
contractverifier/testdata/inner_throw_outer_revert.json
vendored
Normal file
File diff suppressed because one or more lines are too long
60
contractverifier/testdata/oog.json
vendored
Normal file
60
contractverifier/testdata/oog.json
vendored
Normal file
File diff suppressed because one or more lines are too long
58
contractverifier/testdata/revert.json
vendored
Normal file
58
contractverifier/testdata/revert.json
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"context": {
|
||||||
|
"difficulty": "3665057456",
|
||||||
|
"gasLimit": "5232723",
|
||||||
|
"miner": "0xf4d8e706cfb25c0decbbdd4d2e2cc10c66376a3f",
|
||||||
|
"number": "2294501",
|
||||||
|
"timestamp": "1513673601"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"alloc": {
|
||||||
|
"0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9": {
|
||||||
|
"balance": "0x2a3fc32bcc019283",
|
||||||
|
"code": "0x",
|
||||||
|
"nonce": "10",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"0xabbcd5b340c80b5f1c0545c04c987b87310296ae": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"code": "0x606060405236156100755763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416632d0335ab811461007a578063548db174146100ab5780637f649783146100fc578063b092145e1461014d578063c3f44c0a14610186578063c47cf5de14610203575b600080fd5b341561008557600080fd5b610099600160a060020a0360043516610270565b60405190815260200160405180910390f35b34156100b657600080fd5b6100fa600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061028f95505050505050565b005b341561010757600080fd5b6100fa600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061029e95505050505050565b005b341561015857600080fd5b610172600160a060020a03600435811690602435166102ad565b604051901515815260200160405180910390f35b341561019157600080fd5b6100fa6004803560ff1690602480359160443591606435600160a060020a0316919060a49060843590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965050509235600160a060020a031692506102cd915050565b005b341561020e57600080fd5b61025460046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061056a95505050505050565b604051600160a060020a03909116815260200160405180910390f35b600160a060020a0381166000908152602081905260409020545b919050565b61029a816000610594565b5b50565b61029a816001610594565b5b50565b600160209081526000928352604080842090915290825290205460ff1681565b60008080600160a060020a038416158061030d5750600160a060020a038085166000908152600160209081526040808320339094168352929052205460ff165b151561031857600080fd5b6103218561056a565b600160a060020a038116600090815260208190526040808220549295507f19000000000000000000000000000000000000000000000000000000000000009230918891908b908b90517fff000000000000000000000000000000000000000000000000000000000000008089168252871660018201526c01000000000000000000000000600160a060020a038088168202600284015286811682026016840152602a8301869052841602604a820152605e810182805190602001908083835b6020831061040057805182525b601f1990920191602091820191016103e0565b6001836020036101000a0380198251168184511617909252505050919091019850604097505050505050505051809103902091506001828a8a8a6040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f1151561049957600080fd5b5050602060405103519050600160a060020a03838116908216146104bc57600080fd5b600160a060020a0380841660009081526020819052604090819020805460010190559087169086905180828051906020019080838360005b8381101561050d5780820151818401525b6020016104f4565b50505050905090810190601f16801561053a5780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008661646e5a03f1915050151561055e57600080fd5b5b505050505050505050565b600060248251101561057e5750600061028a565b600160a060020a0360248301511690505b919050565b60005b825181101561060157600160a060020a033316600090815260016020526040812083918584815181106105c657fe5b90602001906020020151600160a060020a031681526020810191909152604001600020805460ff19169115159190911790555b600101610597565b5b5050505600a165627a7a723058200027e8b695e9d2dea9f3629519022a69f3a1d23055ce86406e686ea54f31ee9c0029",
|
||||||
|
"nonce": "1",
|
||||||
|
"storage": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"byzantiumBlock": 1700000,
|
||||||
|
"chainId": 3,
|
||||||
|
"daoForkSupport": true,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
|
||||||
|
"eip155Block": 10,
|
||||||
|
"eip158Block": 10,
|
||||||
|
"ethash": {},
|
||||||
|
"homesteadBlock": 0
|
||||||
|
},
|
||||||
|
"difficulty": "3672229776",
|
||||||
|
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
|
||||||
|
"gasLimit": "5227619",
|
||||||
|
"hash": "0xa07b3d6c6bf63f5f981016db9f2d1d93033833f2c17e8bf7209e85f1faf08076",
|
||||||
|
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
|
||||||
|
"mixHash": "0x806e151ce2817be922e93e8d5921fa0f0d0fd213d6b2b9a3fa17458e74a163d0",
|
||||||
|
"nonce": "0xbc5d43adc2c30c7d",
|
||||||
|
"number": "2294500",
|
||||||
|
"stateRoot": "0xca645b335888352ef9d8b1ef083e9019648180b259026572e3139717270de97d",
|
||||||
|
"timestamp": "1513673552",
|
||||||
|
"totalDifficulty": "7160066586979149"
|
||||||
|
},
|
||||||
|
"input": "0xf9018b0a8505d21dba00832dc6c094abbcd5b340c80b5f1c0545c04c987b87310296ae80b9012473b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988000000000000000000000000000000000000000000000000000000000000000000000000000000001ba0fd659d76a4edbd2a823e324c93f78ad6803b30ff4a9c8bce71ba82798975c70ca06571eecc0b765688ec6c78942c5ee8b585e00988c0141b518287e9be919bc48a",
|
||||||
|
"result": {
|
||||||
|
"error": "execution reverted",
|
||||||
|
"from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9",
|
||||||
|
"gas": "0x2d55e8",
|
||||||
|
"gasUsed": "0xc3",
|
||||||
|
"input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae",
|
||||||
|
"type": "CALL",
|
||||||
|
"value": "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
64
contractverifier/testdata/revert_reason.json
vendored
Normal file
64
contractverifier/testdata/revert_reason.json
vendored
Normal file
File diff suppressed because one or more lines are too long
75
contractverifier/testdata/selfdestruct.json
vendored
Normal file
75
contractverifier/testdata/selfdestruct.json
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"context": {
|
||||||
|
"difficulty": "3502894804",
|
||||||
|
"gasLimit": "4722976",
|
||||||
|
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
|
||||||
|
"number": "2289806",
|
||||||
|
"timestamp": "1513601314"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"alloc": {
|
||||||
|
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"code": "0x",
|
||||||
|
"nonce": "22",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
|
||||||
|
"balance": "0x4d87094125a369d9bd5",
|
||||||
|
"code": "0x61deadff",
|
||||||
|
"nonce": "1",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
|
||||||
|
"balance": "0x1780d77678137ac1b775",
|
||||||
|
"code": "0x",
|
||||||
|
"nonce": "29072",
|
||||||
|
"storage": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"byzantiumBlock": 1700000,
|
||||||
|
"chainId": 3,
|
||||||
|
"daoForkSupport": true,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
|
||||||
|
"eip155Block": 10,
|
||||||
|
"eip158Block": 10,
|
||||||
|
"ethash": {},
|
||||||
|
"homesteadBlock": 0
|
||||||
|
},
|
||||||
|
"difficulty": "3509749784",
|
||||||
|
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
|
||||||
|
"gasLimit": "4727564",
|
||||||
|
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
|
||||||
|
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
|
||||||
|
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
|
||||||
|
"nonce": "0x4eb12e19c16d43da",
|
||||||
|
"number": "2289805",
|
||||||
|
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
|
||||||
|
"timestamp": "1513601261",
|
||||||
|
"totalDifficulty": "7143276353481064"
|
||||||
|
},
|
||||||
|
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
|
||||||
|
"result": {
|
||||||
|
"calls": [
|
||||||
|
{
|
||||||
|
"from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||||
|
"gas": "0x0",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"input": "0x",
|
||||||
|
"to": "0x000000000000000000000000000000000000dEaD",
|
||||||
|
"type": "SELFDESTRUCT",
|
||||||
|
"value": "0x4d87094125a369d9bd5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
|
||||||
|
"gas": "0x10738",
|
||||||
|
"gasUsed": "0x7533",
|
||||||
|
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
|
||||||
|
"output": "0x",
|
||||||
|
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||||
|
"type": "CALL",
|
||||||
|
"value": "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
80
contractverifier/testdata/simple.json
vendored
Normal file
80
contractverifier/testdata/simple.json
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"context": {
|
||||||
|
"difficulty": "3502894804",
|
||||||
|
"gasLimit": "4722976",
|
||||||
|
"miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724",
|
||||||
|
"number": "2289806",
|
||||||
|
"timestamp": "1513601314"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"alloc": {
|
||||||
|
"0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": {
|
||||||
|
"balance": "0x0",
|
||||||
|
"code": "0x",
|
||||||
|
"nonce": "22",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": {
|
||||||
|
"balance": "0x4d87094125a369d9bd5",
|
||||||
|
"code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029",
|
||||||
|
"nonce": "1",
|
||||||
|
"storage": {
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb",
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000",
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c",
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": {
|
||||||
|
"balance": "0x1780d77678137ac1b775",
|
||||||
|
"code": "0x",
|
||||||
|
"nonce": "29072",
|
||||||
|
"storage": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"byzantiumBlock": 1700000,
|
||||||
|
"chainId": 3,
|
||||||
|
"daoForkSupport": true,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d",
|
||||||
|
"eip155Block": 10,
|
||||||
|
"eip158Block": 10,
|
||||||
|
"ethash": {},
|
||||||
|
"homesteadBlock": 0
|
||||||
|
},
|
||||||
|
"difficulty": "3509749784",
|
||||||
|
"extraData": "0x4554482e45544846414e532e4f52472d4641313738394444",
|
||||||
|
"gasLimit": "4727564",
|
||||||
|
"hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440",
|
||||||
|
"miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3",
|
||||||
|
"mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada",
|
||||||
|
"nonce": "0x4eb12e19c16d43da",
|
||||||
|
"number": "2289805",
|
||||||
|
"stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f",
|
||||||
|
"timestamp": "1513601261",
|
||||||
|
"totalDifficulty": "7143276353481064"
|
||||||
|
},
|
||||||
|
"input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4",
|
||||||
|
"result": {
|
||||||
|
"calls": [
|
||||||
|
{
|
||||||
|
"from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||||
|
"gas": "0x6d05",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"input": "0x",
|
||||||
|
"to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
|
||||||
|
"type": "CALL",
|
||||||
|
"value": "0x6f05b59d3b20000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
|
||||||
|
"gas": "0x10738",
|
||||||
|
"gasUsed": "0x3ef9",
|
||||||
|
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
|
||||||
|
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
|
||||||
|
"type": "CALL",
|
||||||
|
"value": "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
62
contractverifier/testdata/throw.json
vendored
Normal file
62
contractverifier/testdata/throw.json
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -176,6 +176,15 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
return nil, gas, ErrInsufficientBalance
|
return nil, gas, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
// Verify call function.
|
||||||
|
// It must be verified before evm.stateDB snapshot for avoiding reverting to snapshot.
|
||||||
|
// It doesn't consume gas.
|
||||||
|
if evm.Config.ContractVerifier != nil {
|
||||||
|
if err := evm.Config.ContractVerifier.Verify(evm.StateDB, CALL, caller.Address(), addr, input, value); err != nil {
|
||||||
|
return nil, gas, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
p, isPrecompile := evm.precompile(addr)
|
p, isPrecompile := evm.precompile(addr)
|
||||||
|
|
||||||
|
|
@ -255,6 +264,14 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
return nil, gas, ErrInsufficientBalance
|
return nil, gas, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
// Verify call function.
|
||||||
|
// It must be verified before evm.stateDB snapshot for avoiding reverting to snapshot.
|
||||||
|
// It doesn't consume gas.
|
||||||
|
if evm.Config.ContractVerifier != nil {
|
||||||
|
if err := evm.Config.ContractVerifier.Verify(evm.StateDB, CALLCODE, caller.Address(), addr, input, value); err != nil {
|
||||||
|
return nil, gas, err
|
||||||
|
}
|
||||||
|
}
|
||||||
var snapshot = evm.StateDB.Snapshot()
|
var snapshot = evm.StateDB.Snapshot()
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
|
|
@ -291,6 +308,14 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, ErrDepth
|
||||||
}
|
}
|
||||||
|
// Verify call function.
|
||||||
|
// It must be verified before evm.stateDB snapshot for avoiding reverting to snapshot.
|
||||||
|
// It doesn't consume gas.
|
||||||
|
if evm.Config.ContractVerifier != nil {
|
||||||
|
if err := evm.Config.ContractVerifier.Verify(evm.StateDB, DELEGATECALL, caller.Address(), addr, input, big0); err != nil {
|
||||||
|
return nil, gas, err
|
||||||
|
}
|
||||||
|
}
|
||||||
var snapshot = evm.StateDB.Snapshot()
|
var snapshot = evm.StateDB.Snapshot()
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
|
|
@ -325,6 +350,14 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, ErrDepth
|
||||||
}
|
}
|
||||||
|
// Verify call function.
|
||||||
|
// It must be verified before evm.stateDB snapshot for avoiding reverting to snapshot.
|
||||||
|
// It doesn't consume gas.
|
||||||
|
if evm.Config.ContractVerifier != nil {
|
||||||
|
if err := evm.Config.ContractVerifier.Verify(evm.StateDB, STATICCALL, caller.Address(), addr, input, big0); err != nil {
|
||||||
|
return nil, gas, err
|
||||||
|
}
|
||||||
|
}
|
||||||
// We take a snapshot here. This is a bit counter-intuitive, and could probably be skipped.
|
// We take a snapshot here. This is a bit counter-intuitive, and could probably be skipped.
|
||||||
// However, even a staticcall is considered a 'touch'. On mainnet, static calls were introduced
|
// However, even a staticcall is considered a 'touch'. On mainnet, static calls were introduced
|
||||||
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
||||||
|
|
|
||||||
|
|
@ -789,6 +789,13 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||||
func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
beneficiary := scope.Stack.pop()
|
beneficiary := scope.Stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
||||||
|
// Verify SELFDESTRUCT opCode.
|
||||||
|
// It doesn't consume gas.
|
||||||
|
if interpreter.evm.Config.ContractVerifier != nil {
|
||||||
|
if err := interpreter.evm.Config.ContractVerifier.Verify(interpreter.evm.StateDB, SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), nil, balance); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||||
interpreter.evm.StateDB.Suicide(scope.Contract.Address())
|
interpreter.evm.StateDB.Suicide(scope.Contract.Address())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,12 @@ import (
|
||||||
|
|
||||||
// Config are the configuration options for the Interpreter
|
// Config are the configuration options for the Interpreter
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Debug bool // Enables debugging
|
Debug bool // Enables debugging
|
||||||
Tracer Tracer // Opcode logger
|
Tracer Tracer // Opcode logger
|
||||||
NoRecursion bool // Disables call, callcode, delegate call and create
|
ContractVerifier ContractVerifier // evm operation testdata
|
||||||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
NoRecursion bool // Disables call, callcode, delegate call and create
|
||||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||||
|
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||||
|
|
||||||
JumpTable [256]*operation // EVM instruction table, automatically populated if unset
|
JumpTable [256]*operation // EVM instruction table, automatically populated if unset
|
||||||
|
|
||||||
|
|
|
||||||
10
core/vm/ok_verifier.go
Normal file
10
core/vm/ok_verifier.go
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContractVerifier interface {
|
||||||
|
Verify(stateDB StateDB, op OpCode, from, to common.Address, input []byte, value *big.Int) error
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue