Skip to content

Commit

Permalink
Merge pull request #112 from blocknative/TS_nbc
Browse files Browse the repository at this point in the history
Decoding features and fixes
  • Loading branch information
tyler-smith authored Sep 18, 2023
2 parents 14d132e + d706b39 commit d7e3f8a
Show file tree
Hide file tree
Showing 25 changed files with 2,650 additions and 1,333 deletions.
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

0 comments on commit d7e3f8a

Please sign in to comment.