Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decoding features and fixes #112

Merged
merged 11 commits into from
Sep 18, 2023
15 changes: 12 additions & 3 deletions eth/filters/trace_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,34 +77,43 @@ func (api *FilterAPI) NewPendingTransactionsWithTrace(ctx context.Context, trace
tracedTxs = make([]*RPCTransaction, 0, len(txs))
blockNumber = hexutil.Big(*header.Number)
blockHash = header.Hash()
txIndex = hexutil.Uint64(0)
)

statedb, err := api.sys.chain.State()
if err != nil {
log.Error("NewPendingTransactionsWithTrace failed to get state", "err", err)
log.Error("failed to get state", "err", err)
return
}

for _, tx := range txs {
msg, _ = core.TransactionToMessage(tx, signer, header.BaseFee)
if err != nil {
log.Error("NewPendingTransactionsWithTrace failed to create tx message", "err", err, "tx", tx.Hash())
log.Error("failed to create tx message", "err", err, "tx", tx.Hash())
continue
}

traceCtx.TxHash = tx.Hash()
trace, err := traceTx(msg, traceCtx, blockCtx, chainConfig, statedb, tracerOpts)
if err != nil {
log.Error("NewPendingTransactionsWithTrace failed to trace tx", "err", err, "tx", tx.Hash())
log.Error("failed to trace tx", "err", err, "tx", tx.Hash())
continue
}

gasPrice := hexutil.Big(*tx.GasPrice())
rpcTx := newRPCPendingTransaction(tx)
rpcTx.BlockHash = &blockHash
rpcTx.BlockNumber = &blockNumber
rpcTx.TransactionIndex = &txIndex
rpcTx.Trace = trace
rpcTx.GasPrice = &gasPrice
tracedTxs = append(tracedTxs, rpcTx)
}

if len(tracedTxs) == 0 {
continue
}

notifier.Notify(rpcSub.ID, tracedTxs)
case <-rpcSub.Err():
return
Expand Down
97 changes: 17 additions & 80 deletions eth/tracers/blocknative/blocknative.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package blocknative

import (
"encoding/json"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/blocknative/decoder"
Expand All @@ -20,6 +17,7 @@ type Tracer interface {
// TracerOpts configure the tracer to save or ignore various aspects of a transaction execution.
type TracerOpts struct {
Logs bool `json:"logs"`
Decode bool `json:"decode"`
BalanceChanges bool `json:"balanceChanges"`

// DisableBlockContext disables the block context in the trace.
Expand All @@ -30,10 +28,10 @@ type TracerOpts struct {
// Trace contains all the accumulated details of a transaction execution.
type Trace struct {
CallFrame
BlockContext *BlockContext `json:"blockContext,omitempty"`
Logs []CallLog `json:"logs,omitempty"`
Time string `json:"time,omitempty"`
BalanceChanges NetBalanceChanges `json:"balanceChanges"`
BlockContext *BlockContext `json:"blockContext,omitempty"`
Logs []CallLog `json:"logs,omitempty"`
Time string `json:"time,omitempty"`
BalanceChanges decoder.NetBalanceChanges `json:"balanceChanges"`
}

// BlockContext contains information about the block we simulate transactions in.
Expand All @@ -48,17 +46,18 @@ type BlockContext struct {
}

type CallFrame struct {
Type string `json:"type"`
From string `json:"from"`
To string `json:"to,omitempty"`
Value string `json:"value,omitempty"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
Input string `json:"input"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
ErrorReason string `json:"errorReason,omitempty"`
Calls []CallFrame `json:"calls,omitempty"`
Type string `json:"type"`
From string `json:"from"`
To string `json:"to,omitempty"`
Value string `json:"value,omitempty"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
Input string `json:"input"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
ErrorReason string `json:"errorReason,omitempty"`
Calls []CallFrame `json:"calls,omitempty"`
Decoded *decoder.CallFrame `json:"decoded,omitempty"`
}

// CallLog represents a single log entry from the receipt of a transaction.
Expand All @@ -72,65 +71,3 @@ type CallLog struct {
// Topics is a slice of up to 4 32byte words provided with the log.
Topics []common.Hash `json:"topics"`
}

// NetBalanceChanges is a list of account balance changes.
type NetBalanceChanges []AccountBalanceChanges

// AccountBalanceChanges is a list of balance changes for a single account.
type AccountBalanceChanges struct {
Address common.Address `json:"address"`
BalanceChanges []BalanceChange `json:"balanceChanges"`
}

// BalanceChange is a change in an account's balance for a single asset.
type BalanceChange struct {
Delta *Amount `json:"delta"`
Asset *decoder.Asset `json:"asset"`
Breakdown []AssetTransferEvent `json:"breakdown"`
}

// AssetTransferEvent is a single transfer of an asset.
type AssetTransferEvent struct {
Counterparty common.Address `json:"counterparty"`
Amount *Amount `json:"amount"`
}

type Amount big.Int

func NewAmount(i *big.Int) *Amount {
return (*Amount)(i)
}

func (a *Amount) Add(x *Amount, y *big.Int) {
a.ToInt().Add(x.ToInt(), y)
}

func (a *Amount) ToInt() *big.Int {
return (*big.Int)(a)
}

func (a *Amount) String() string {
return a.ToInt().String()
}

func (a *Amount) MarshalJSON() ([]byte, error) {
return json.Marshal(a.ToInt().String())
}

func (a *Amount) UnmarshalJSON(data []byte) error {
if data == nil || len(data) == 0 {
*a = *NewAmount(big.NewInt(0))
return nil
}

var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
aInt, ok := new(big.Int).SetString(s, 10)
if !ok {
return fmt.Errorf("failed to convert string to Amount")
}
*a = *(*Amount)(aInt)
return nil
}
61 changes: 61 additions & 0 deletions eth/tracers/blocknative/decoder/abi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package decoder

import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/log"
)

var (
abiTypes = struct {
_string abi.Type
_address abi.Type
_uint256 abi.Type
_uint256Array abi.Type
_bytes abi.Type
}{}

abiArgs = struct {
singleString abi.Arguments
batchTransfer abi.Arguments
}{}
)

func init() {
if err := initABITypes(); err != nil {
log.Error("failed to initialize abi types", "err", err)
}
initABIArgs()
}

// initABITypes initializes all the abiTypes.
func initABITypes() error {
var err error
if abiTypes._string, err = abi.NewType("string", "", nil); err != nil {
return err
}
if abiTypes._address, err = abi.NewType("address", "", nil); err != nil {
return err
}
if abiTypes._uint256, err = abi.NewType("uint256", "", nil); err != nil {
return err
}
if abiTypes._uint256Array, err = abi.NewType("uint256[]", "", nil); err != nil {
return err
}
if abiTypes._bytes, err = abi.NewType("bytes", "", nil); err != nil {
return err
}
return nil
}

// initABIArgs initializes all the abiArgs.
func initABIArgs() {
abiArgs.singleString = abi.Arguments{abi.Argument{Type: abiTypes._string, Name: "name"}}
abiArgs.batchTransfer = abi.Arguments{
abi.Argument{Type: abiTypes._address, Name: "from"},
abi.Argument{Type: abiTypes._address, Name: "to"},
abi.Argument{Type: abiTypes._uint256Array, Name: "tokenIDs"},
abi.Argument{Type: abiTypes._uint256Array, Name: "values"},
abi.Argument{Type: abiTypes._bytes, Name: "data"},
}
}
Loading