forked from cerc-io/plugeth
eth/tracer: extend create2 (#18318)
* eth/tracer: extend create2 * eth/tracers: fix create2-flaw in prestate_tracer * eth/tracers: fix test * eth/tracers: update assets
This commit is contained in:
parent
c1c4301121
commit
e8ff318205
File diff suppressed because one or more lines are too long
@ -38,7 +38,7 @@
|
|||||||
var op = log.op.toString();
|
var op = log.op.toString();
|
||||||
}
|
}
|
||||||
// If a new contract is being created, add to the call stack
|
// If a new contract is being created, add to the call stack
|
||||||
if (syscall && op == 'CREATE') {
|
if (syscall && (op == 'CREATE' || op == "CREATE2")) {
|
||||||
var inOff = log.stack.peek(1).valueOf();
|
var inOff = log.stack.peek(1).valueOf();
|
||||||
var inEnd = inOff + log.stack.peek(2).valueOf();
|
var inEnd = inOff + log.stack.peek(2).valueOf();
|
||||||
|
|
||||||
@ -116,7 +116,7 @@
|
|||||||
// Pop off the last call and get the execution results
|
// Pop off the last call and get the execution results
|
||||||
var call = this.callstack.pop();
|
var call = this.callstack.pop();
|
||||||
|
|
||||||
if (call.type == 'CREATE') {
|
if (call.type == 'CREATE' || call.type == "CREATE2") {
|
||||||
// If the call was a CREATE, retrieve the contract address and output code
|
// If the call was a CREATE, retrieve the contract address and output code
|
||||||
call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16);
|
call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16);
|
||||||
delete call.gasIn; delete call.gasCost;
|
delete call.gasIn; delete call.gasCost;
|
||||||
|
@ -86,6 +86,14 @@
|
|||||||
var from = log.contract.getAddress();
|
var from = log.contract.getAddress();
|
||||||
this.lookupAccount(toContract(from, db.getNonce(from)), db);
|
this.lookupAccount(toContract(from, db.getNonce(from)), db);
|
||||||
break;
|
break;
|
||||||
|
case "CREATE2":
|
||||||
|
var from = log.contract.getAddress();
|
||||||
|
// stack: salt, size, offset, endowment
|
||||||
|
var offset = log.stack.peek(1).valueOf()
|
||||||
|
var size = log.stack.peek(2).valueOf()
|
||||||
|
var end = offset + size
|
||||||
|
this.lookupAccount(toContract2(from, log.stack.peek(3).toString(16), log.memory.slice(offset, end)), db);
|
||||||
|
break;
|
||||||
case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL":
|
case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL":
|
||||||
this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db);
|
this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db);
|
||||||
break;
|
break;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore ((tracers)|(assets)).go ./...
|
//go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore tracers.go -ignore assets.go ./...
|
||||||
//go:generate gofmt -s -w assets.go
|
//go:generate gofmt -s -w assets.go
|
||||||
|
|
||||||
// Package tracers contains the actual JavaScript tracer assets.
|
// Package tracers contains the actual JavaScript tracer assets.
|
||||||
|
@ -367,6 +367,28 @@ func New(code string) (*Tracer, error) {
|
|||||||
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
|
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
|
||||||
return 1
|
return 1
|
||||||
})
|
})
|
||||||
|
tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int {
|
||||||
|
var from common.Address
|
||||||
|
if ptr, size := ctx.GetBuffer(-3); ptr != nil {
|
||||||
|
from = common.BytesToAddress(makeSlice(ptr, size))
|
||||||
|
} else {
|
||||||
|
from = common.HexToAddress(ctx.GetString(-3))
|
||||||
|
}
|
||||||
|
// Retrieve salt hex string from js stack
|
||||||
|
salt := common.HexToHash(ctx.GetString(-2))
|
||||||
|
// Retrieve code slice from js stack
|
||||||
|
var code []byte
|
||||||
|
if ptr, size := ctx.GetBuffer(-1); ptr != nil {
|
||||||
|
code = common.CopyBytes(makeSlice(ptr, size))
|
||||||
|
} else {
|
||||||
|
code = common.FromHex(ctx.GetString(-1))
|
||||||
|
}
|
||||||
|
codeHash := crypto.Keccak256(code)
|
||||||
|
ctx.Pop3()
|
||||||
|
contract := crypto.CreateAddress2(from, salt, codeHash)
|
||||||
|
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
|
||||||
|
return 1
|
||||||
|
})
|
||||||
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
|
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
|
||||||
_, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))]
|
_, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))]
|
||||||
ctx.PushBoolean(ok)
|
ctx.PushBoolean(ok)
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
package tracers
|
package tracers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rand"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -31,7 +33,9 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
)
|
)
|
||||||
@ -116,6 +120,83 @@ type callTracerTest struct {
|
|||||||
Result *callTrace `json:"result"`
|
Result *callTrace `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrestateTracerCreate2(t *testing.T) {
|
||||||
|
unsigned_tx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"),
|
||||||
|
new(big.Int), 5000000, big.NewInt(1), []byte{})
|
||||||
|
|
||||||
|
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err %v", err)
|
||||||
|
}
|
||||||
|
signer := types.NewEIP155Signer(big.NewInt(1))
|
||||||
|
tx, err := types.SignTx(unsigned_tx, signer, privateKeyECDSA)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err %v", err)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
This comes from one of the test-vectors on the Skinny Create2 - EIP
|
||||||
|
|
||||||
|
address 0x00000000000000000000000000000000deadbeef
|
||||||
|
salt 0x00000000000000000000000000000000000000000000000000000000cafebabe
|
||||||
|
init_code 0xdeadbeef
|
||||||
|
gas (assuming no mem expansion): 32006
|
||||||
|
result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7
|
||||||
|
*/
|
||||||
|
origin, _ := signer.Sender(tx)
|
||||||
|
context := vm.Context{
|
||||||
|
CanTransfer: core.CanTransfer,
|
||||||
|
Transfer: core.Transfer,
|
||||||
|
Origin: origin,
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
BlockNumber: new(big.Int).SetUint64(8000000),
|
||||||
|
Time: new(big.Int).SetUint64(5),
|
||||||
|
Difficulty: big.NewInt(0x30000),
|
||||||
|
GasLimit: uint64(6000000),
|
||||||
|
GasPrice: big.NewInt(1),
|
||||||
|
}
|
||||||
|
alloc := core.GenesisAlloc{}
|
||||||
|
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
|
||||||
|
// the address
|
||||||
|
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{
|
||||||
|
Nonce: 1,
|
||||||
|
Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"),
|
||||||
|
Balance: big.NewInt(1),
|
||||||
|
}
|
||||||
|
alloc[origin] = core.GenesisAccount{
|
||||||
|
Nonce: 1,
|
||||||
|
Code: []byte{},
|
||||||
|
Balance: big.NewInt(500000000000000),
|
||||||
|
}
|
||||||
|
statedb := tests.MakePreState(ethdb.NewMemDatabase(), alloc)
|
||||||
|
// Create the tracer, the EVM environment and run it
|
||||||
|
tracer, err := New("prestateTracer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
|
}
|
||||||
|
evm := vm.NewEVM(context, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
|
|
||||||
|
msg, err := tx.AsMessage(signer)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
// Retrieve the trace result and compare against the etalon
|
||||||
|
res, err := tracer.GetResult()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to retrieve trace result: %v", err)
|
||||||
|
}
|
||||||
|
ret := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(res, &ret); err != nil {
|
||||||
|
t.Fatalf("failed to unmarshal trace result: %v", err)
|
||||||
|
}
|
||||||
|
if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has {
|
||||||
|
t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Iterates over all the input-output datasets in the tracer test harness and
|
// Iterates over all the input-output datasets in the tracer test harness and
|
||||||
// runs the JavaScript tracers against them.
|
// runs the JavaScript tracers against them.
|
||||||
func TestCallTracer(t *testing.T) {
|
func TestCallTracer(t *testing.T) {
|
||||||
@ -185,8 +266,9 @@ func TestCallTracer(t *testing.T) {
|
|||||||
if err := json.Unmarshal(res, ret); err != nil {
|
if err := json.Unmarshal(res, ret); err != nil {
|
||||||
t.Fatalf("failed to unmarshal trace result: %v", err)
|
t.Fatalf("failed to unmarshal trace result: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(ret, test.Result) {
|
if !reflect.DeepEqual(ret, test.Result) {
|
||||||
t.Fatalf("trace mismatch: have %+v, want %+v", ret, test.Result)
|
t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user