Skip to content

Commit

Permalink
Apply go-ethereum#18318
Browse files Browse the repository at this point in the history
To tracing CREATE2 instruction,
ethereum/go-ethereum@e8ff318
is applied.

ethereum/go-ethereum#18318
  • Loading branch information
kjhman21 authored and KimKyungup committed Apr 27, 2020
1 parent b53b871 commit 64b1fe6
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 29 deletions.
27 changes: 2 additions & 25 deletions node/cn/tracers/internal/tracers/assets.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions node/cn/tracers/internal/tracers/call_tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
var op = log.op.toString();
}
// 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 inEnd = inOff + log.stack.peek(2).valueOf();

Expand Down Expand Up @@ -142,7 +142,7 @@
// Pop off the last call and get the execution results
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
call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16);
delete call.gasIn; delete call.gasCost;
Expand Down
8 changes: 8 additions & 0 deletions node/cn/tracers/internal/tracers/prestate_tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@
var from = log.contract.getAddress();
this.lookupAccount(toContract(from, db.getNonce(from)), db);
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":
this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db);
break;
Expand Down
2 changes: 1 addition & 1 deletion node/cn/tracers/internal/tracers/tracers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// 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/>.

//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

// Package tracers contains the actual JavaScript tracer assets.
Expand Down
22 changes: 22 additions & 0 deletions node/cn/tracers/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,28 @@ func New(code string) (*Tracer, error) {
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
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 {
_, ok := vm.PrecompiledContractsCypress[common.BytesToAddress(popSlice(ctx))]
ctx.PushBoolean(ok)
Expand Down
81 changes: 80 additions & 1 deletion node/cn/tracers/tracers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package tracers

import (
"crypto/ecdsa"
"crypto/rand"
"encoding/json"
"github.com/klaytn/klaytn/blockchain"
"github.com/klaytn/klaytn/blockchain/types"
Expand All @@ -29,6 +31,7 @@ import (
"github.com/klaytn/klaytn/common/hexutil"
"github.com/klaytn/klaytn/common/math"
"github.com/klaytn/klaytn/crypto"
"github.com/klaytn/klaytn/params"
"github.com/klaytn/klaytn/ser/rlp"
"github.com/klaytn/klaytn/storage/database"
"github.com/klaytn/klaytn/tests"
Expand Down Expand Up @@ -126,6 +129,82 @@ type callTracerTest struct {
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: blockchain.CanTransfer,
Transfer: blockchain.Transfer,
Origin: origin,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000),
Time: new(big.Int).SetUint64(5),
BlockScore: big.NewInt(0x30000),
GasLimit: uint64(6000000),
GasPrice: big.NewInt(1),
}
alloc := blockchain.GenesisAlloc{}
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
// the address
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = blockchain.GenesisAccount{
Nonce: 1,
Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"),
Balance: big.NewInt(1),
}
alloc[origin] = blockchain.GenesisAccount{
Nonce: 1,
Code: []byte{},
Balance: big.NewInt(500000000000000),
}
statedb := tests.MakePreState(database.NewMemoryDBManager(), 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.AsMessageWithAccountKeyPicker(signer, statedb, context.BlockNumber.Uint64())
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
st := blockchain.NewStateTransition(evm, msg)
if _, _, kerr := st.TransitionDb(); kerr.ErrTxInvalid != nil {
t.Fatalf("failed to execute transaction: %v", kerr.ErrTxInvalid)
}
// 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
// runs the JavaScript tracers against them.
func TestCallTracer(t *testing.T) {
Expand Down Expand Up @@ -221,7 +300,7 @@ func TestCallTracer(t *testing.T) {
t.Fatalf("failed to unmarshal trace result: %v", err)
}
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)
}
})
}
Expand Down

0 comments on commit 64b1fe6

Please sign in to comment.