The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
woop/hmy/tracers/block_tracer_test.go

296 lines
14 KiB

package tracers
import (
"bytes"
"encoding/json"
"errors"
"math/big"
"strconv"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/utils"
)
var TestJsonsMock = []byte(`{"14054302":[{"blockNumber":14054302,"blockHash":"0x04d7a0d62d3211151db0dadcaebcb1686c4a3df0e551a00c023c651546293975","transactionHash":"0xce49e42e0fbd37a0cfd08c2da3f1acc371ddbc02c428afa123a43663e57953d7","transactionPosition":0,"subtraces":0,"traceAddress":[0],"type":"suicide","action":{"refundAddress":"0x12e49d93588e0056bd25530c3b1e8aac68f4b70a","balance":"0x0","address":"0x7006c42d6fa41844baa53b0388f9542e634cf55a"},"result":null}],"14833359":[{"blockNumber":14833359,"blockHash":"0x6d6660f3d042a145c7f95c408f28cbf036a18eaf603161c2c00ca3f6041d8b52","transactionHash":"0x9fd0daef346c72d51f7482ddc9a466caf52fa6a116ed13ee0c003e57e632b7c0","transactionPosition":0,"subtraces":0,"traceAddress":[],"type":"create","action":{"from":"0x8520021f89450394244cd4abda4cfe2f1b0ef61c","gas":"0x1017d","init":"0x608060405234801561001057600080fd5b50610149806100206000396000f3fe6080604052600436106100295760003560e01c80630c2ad69c1461002e57806315d55b281461007a575b600080fd5b6100646004803603604081101561004457600080fd5b810190808035906020019092919080359060200190929190505050610091565b6040518082815260200191505060405180910390f35b34801561008657600080fd5b5061008f6100a5565b005b600081838161009c57fe5b04905092915050565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f68656c6c6f00000000000000000000000000000000000000000000000000000081525060200191505060405180910390fdfea26469706673582212202f9958b958267c4ed653e54dc0161cfb9b772209cbe086f4a9ac3d967f22f09564736f6c634300060c0033","value":"0x0"},"result":{"address":"0xf29fcf3a375ce5dd1c58f0e8a584ab5d782cc12b","code":"0x6080604052600436106100295760003560e01c80630c2ad69c1461002e57806315d55b281461007a575b600080fd5b6100646004803603604081101561004457600080fd5b810190808035906020019092919080359060200190929190505050610091565b6040518082815260200191505060405180910390f35b34801561008657600080fd5b5061008f6100a5565b005b600081838161009c57fe5b04905092915050565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260058152602001807f68656c6c6f00000000000000000000000000000000000000000000000000000081525060200191505060405180910390fdfea26469706673582212202f9958b958267c4ed653e54dc0161cfb9b772209cbe086f4a9ac3d967f22f09564736f6c634300060c0033","gasUsed":"0x1017d"}},{"blockNumber":14833359,"blockHash":"0x6d6660f3d042a145c7f95c408f28cbf036a18eaf603161c2c00ca3f6041d8b52","transactionHash":"0xc3b81fa2f6786ffd11a588b9d951a39adb46b6e29abad819b0cb09ee32ea7072","transactionPosition":1,"subtraces":2,"traceAddress":[],"type":"call","action":{"callType":"call","value":"0x0","to":"0x4596817192fbbf0142c576ed3e7cfc0e8f40bbbe","gas":"0x2b71c","from":"0x87946ddc76a4c0a75c8ca1f63dffd0612ae6458c","input":"0x1801fbe5aebcf6e3d785238603dd88bb43cbdfcfeb51c95b570113ee65d2f9271d3b59510000000dcdf493a5e1610e23c037bc4c4e04ab9a6d8fe9d0d462ecd8d45643ac"},"result":{"output":"0x0000000000000000000000000000000000000000000000000000000000000001","gasUsed":"0x13c58"}}]}`)
type JsonCallAction struct {
CallType string `json:"callType"`
Value string `json:"value"`
From common.Address `json:"from"`
To common.Address `json:"to"`
Gas string `json:"gas"`
Input string `json:"input"`
}
type JsonCreateAction struct {
From common.Address `json:"from"`
Value string `json:"value"`
Gas string `json:"gas"`
Init string `json:"init"`
}
type JsonSuicideAction struct {
RefundAddress common.Address `json:"refundAddress"`
Balance string `json:"balance"`
Address common.Address `json:"address"`
}
type JsonCallOutput struct {
Output string `json:"output"`
GasUsed string `json:"gasUsed"`
}
type JsonCreateOutput struct {
Address common.Address `json:"address"`
Code string `json:"code"`
GasUsed string `json:"gasUsed"`
}
type JsonTrace struct {
BlockNumber uint64 `json:"blockNumber"`
BlockHash common.Hash `json:"blockHash"`
TransactionHash common.Hash `json:"transactionHash"`
TransactionPosition uint `json:"transactionPosition"`
Subtraces uint `json:"subtraces"`
TraceAddress []uint `json:"traceAddress"`
Typ string `json:"type"`
Action json.RawMessage `json:"action"`
Result json.RawMessage `json:"result"`
Err string `json:"error"`
Revert string `json:"revert"`
}
// this function only used by test
func initFromJson(ts *TraceBlockStorage, bytes []byte) {
var actionObjs []JsonTrace
var txs []*TxStorage
var tx *TxStorage
json.Unmarshal(bytes, &actionObjs)
for _, obj := range actionObjs {
ac := action{}
if len(obj.Err) > 0 {
ac.err = errors.New(obj.Err)
ac.revert = utils.FromHex(obj.Revert)
}
if obj.Typ == "call" {
callAc := &JsonCallAction{}
err := json.Unmarshal(obj.Action, callAc)
if err != nil {
panic(err)
}
switch callAc.CallType {
case "staticcall":
ac.op = vm.STATICCALL
case "call":
ac.op = vm.CALL
case "callcode":
ac.op = vm.CALLCODE
case "delegatecall":
ac.op = vm.DELEGATECALL
}
ac.from = callAc.From
ac.to = callAc.To
ac.value, _ = new(big.Int).SetString(callAc.Value[2:], 16)
ac.gas, _ = strconv.ParseUint(callAc.Gas, 0, 64)
ac.input = utils.FromHex(callAc.Input)
if ac.err == nil {
callOutput := &JsonCallOutput{}
err = json.Unmarshal(obj.Result, callOutput)
if err != nil {
panic(err)
}
ac.output = utils.FromHex(callOutput.Output)
ac.gasUsed, err = strconv.ParseUint(callOutput.GasUsed, 0, 64)
if err != nil {
panic(err)
}
}
}
if obj.Typ == "create" {
ac.op = vm.CREATE
callAc := &JsonCreateAction{}
err := json.Unmarshal(obj.Action, callAc)
if err != nil {
panic(err)
}
callOutput := &JsonCreateOutput{}
err = json.Unmarshal(obj.Result, callOutput)
if err != nil {
panic(err)
}
ac.from = callAc.From
ac.value, _ = new(big.Int).SetString(callAc.Value[2:], 16)
ac.gas, _ = strconv.ParseUint(callAc.Gas, 0, 64)
ac.input = utils.FromHex(callAc.Init)
if ac.err == nil {
ac.to = callOutput.Address
ac.output = utils.FromHex(callOutput.Code)
ac.gasUsed, _ = strconv.ParseUint(callOutput.GasUsed, 0, 64)
}
}
if obj.Typ == "suicide" {
ac.op = vm.SELFDESTRUCT
callAc := &JsonSuicideAction{}
err := json.Unmarshal(obj.Action, callAc)
if err != nil {
panic(err)
}
ac.from = callAc.Address
ac.to = callAc.RefundAddress
ac.value, _ = new(big.Int).SetString(callAc.Balance[2:], 16)
}
ts.Hash = obj.BlockHash
ts.Number = obj.BlockNumber
if tx == nil || tx.Hash != obj.TransactionHash {
tx = &TxStorage{
Hash: obj.TransactionHash,
}
txs = append(txs, tx)
}
acStorage := ac.toStorage(ts)
acStorage.Subtraces = obj.Subtraces
acStorage.TraceAddress = obj.TraceAddress
tx.Storages = append(tx.Storages, acStorage)
}
for _, tx := range txs {
b, err := rlp.EncodeToBytes(tx)
if err != nil {
panic(err)
}
ts.TraceStorages = append(ts.TraceStorages, b)
}
}
func TestStorage(t *testing.T) {
testJsons := make(map[string]json.RawMessage)
var sizeDB []byte
var memDB [][2][]byte
//TestJsonsMock, _ := os.ReadFile("/tmp/out.json")
json.Unmarshal(TestJsonsMock, &testJsons)
for _, testJson := range testJsons {
block := &TraceBlockStorage{
addressIndex: make(map[common.Address]int),
dataIndex: make(map[common.Hash]int),
}
initFromJson(block, testJson)
jsonRaw, err := block.ToJson()
if err != nil {
t.Error(err)
}
if !bytes.Equal(jsonRaw, testJson) {
t.Fatal("restroe failed!")
}
block.ToDB(func(key, data []byte) {
for _, kv := range memDB {
if bytes.Equal(kv[0], key) {
return
}
}
sizeDB = append(sizeDB, key...)
newKey := sizeDB[len(sizeDB)-len(key):]
sizeDB = append(sizeDB, data...)
newData := sizeDB[len(sizeDB)-len(data):]
memDB = append(memDB, [2][]byte{newKey, newData})
})
newBlock := &TraceBlockStorage{
Hash: block.Hash,
addressIndex: make(map[common.Address]int),
dataIndex: make(map[common.Hash]int),
}
newBlock.FromDB(func(key []byte) ([]byte, error) {
for _, kv := range memDB {
k, v := kv[0], kv[1]
if bytes.Equal(k, key) {
return v, nil
}
}
t.Fatalf("key not exist: %x", key)
return nil, nil
})
jsonRaw, err = newBlock.ToJson()
if err != nil {
t.Error(err)
}
if !bytes.Equal(jsonRaw, testJson) {
t.Fatal("restroe failed!")
}
//os.WriteFile("/tmp/trace.raw", sizeDB, os.ModePerm)
}
}
var TestActions = []string{
`{"callType":"call","value":"0x9f2d9ea5d38f03446","to":"0xf012702a5f0e54015362cbca26a26fc90aa832a3","gas":"0x177d97","from":"0x5a42560d64136caef1a92d4c0829c21385f9f182","input":"0xfb3bdb41000000000000000000000000000000000000000000000001a8a909dfcef4000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000005a42560d64136caef1a92d4c0829c21385f9f1820000000000000000000000000000000000000000000000000000000061cecc5c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cf664087a5bb0237a0bad6742852ec6c8d69a27a000000000000000000000000a4e24f10712cec820dd04e35d52f8087a0699d19"}`,
`{"callType":"staticcall","to":"0x3fe7910191e07503a94237303c8c0497549b0b20","gas":"0x17120d","from":"0xf012702a5f0e54015362cbca26a26fc90aa832a3","input":"0x0902f1ac"}`,
`{"callType":"delegatecall","to":"0x4a5dca217eea6ec5f3a2f81859f0698aaf7668b9","gas":"0x215170","from":"0x5f753dcdf9b1ad9aabc1346614d1f4746fd6ce5c","input":"0x6352211e000000000000000000000000000000000000000000000000000000000000bd5e"}`,
`{"from":"0x84eaa517a51445e35a368885da3d30cd9ab2ead4","gas":"0x659087","init":"0x608060405234801561001057600080fd5b5060405161033a38038061033a8339818101604052602081101561003357600080fd5b810190808051906020019092919050505080600081905550506102df8061005b6000396000f3fe6080604052600436106100295760003560e01c80638100626b1461002e5780639eb7a67f1461007c575b600080fd5b61007a6004803603604081101561004457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506100d7565b005b34801561008857600080fd5b506100d56004803603604081101561009f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061020a565b005b60008114156100e557610206565b8173ffffffffffffffffffffffffffffffffffffffff16638100626b6002348161010b57fe5b0430600185036040518463ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506000604051808303818588803b15801561016357600080fd5b505af1158015610177573d6000803e3d6000fd5b50505050508173ffffffffffffffffffffffffffffffffffffffff16639eb7a67f30836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156101ed57600080fd5b505af1158015610201573d6000803e3d6000fd5b505050505b5050565b6001811115610218576102a5565b8173ffffffffffffffffffffffffffffffffffffffff16639eb7a67f83600184016040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561028c57600080fd5b505af11580156102a0573d6000803e3d6000fd5b505050505b505056fea2646970667358221220eada8b07d177afc51b40b49ee90fe29274e3a002f2138a9023a11463dd82d4f164736f6c634300060c003300000000000000000000000000000000000000000000000000000000000001c8","value":"0x0"}`,
`{"refundAddress":"0xf012702a5f0e54015362cbca26a26fc90aa832a3","balance":"0x9f2d9ea5d38f03446","address":"0xf012702a5f0e54015362cbca26a26fc90aa832a3"}`,
}
func unmarshalAction(jsonstr string) (*action, error) {
actionInterface := make(map[string]string)
if err := json.Unmarshal([]byte(jsonstr), &actionInterface); err != nil {
return nil, err
}
var ac action
if callType, exist := actionInterface["callType"]; exist {
ac.from = common.HexToAddress(actionInterface["from"])
ac.to = common.HexToAddress(actionInterface["to"])
ac.gas, _ = strconv.ParseUint(actionInterface["gas"], 0, 64)
ac.input = utils.FromHex(actionInterface["input"])
ac.value = big.NewInt(0)
ac.value.UnmarshalText([]byte(actionInterface["value"]))
switch strings.ToUpper(callType) {
case "CALL":
ac.op = vm.CALL
case "CALLCODE":
ac.op = vm.CALLCODE
case "DELEGATECALL":
ac.op = vm.DELEGATECALL
case "STATICCALL":
ac.op = vm.STATICCALL
}
return &ac, nil
}
if initCode, exist := actionInterface["init"]; exist {
ac.op = vm.CREATE
ac.from = common.HexToAddress(actionInterface["from"])
ac.value = big.NewInt(0)
ac.value.UnmarshalText([]byte(actionInterface["value"]))
ac.gas, _ = strconv.ParseUint(actionInterface["gas"], 0, 64)
ac.input = utils.FromHex(initCode)
return &ac, nil
}
if refundAddress, exist := actionInterface["refundAddress"]; exist {
ac.op = vm.SELFDESTRUCT
ac.from = common.HexToAddress(actionInterface["address"])
ac.to = common.HexToAddress(refundAddress)
ac.value = big.NewInt(0)
ac.value.UnmarshalText([]byte(actionInterface["balance"]))
return &ac, nil
}
return nil, errors.New("invalid action string")
}
func TestActionMarshal(t *testing.T) {
for _, jsonStr := range TestActions {
ac, err := unmarshalAction(jsonStr)
if err != nil {
t.Error(err)
}
_, acJsonStr, _ := ac.toJsonStr()
if jsonStr != *acJsonStr {
t.Errorf("expected %s got %s\n", jsonStr, *acJsonStr)
}
}
}