diff --git a/cmd/rpcdaemon/commands/erigon_api.go b/cmd/rpcdaemon/commands/erigon_api.go index 12b089e2e..d6fd93699 100644 --- a/cmd/rpcdaemon/commands/erigon_api.go +++ b/cmd/rpcdaemon/commands/erigon_api.go @@ -2,6 +2,7 @@ package commands import ( "context" + ethFilters "github.com/ledgerwatch/erigon/eth/filters" "github.com/ledgerwatch/erigon-lib/kv" @@ -27,7 +28,7 @@ type ErigonAPI interface { // Receipt related (see ./erigon_receipts.go) GetLogsByHash(ctx context.Context, hash common.Hash) ([][]*types.Log, error) //GetLogsByNumber(ctx context.Context, number rpc.BlockNumber) ([][]*types.Log, error) - GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) ([]*types.Log, error) + GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) (types.ErigonLogs, error) // WatchTheBurn / reward related (see ./erigon_issuance.go) WatchTheBurn(ctx context.Context, blockNr rpc.BlockNumber) (Issuance, error) diff --git a/cmd/rpcdaemon/commands/erigon_receipts.go b/cmd/rpcdaemon/commands/erigon_receipts.go index 311d0fc43..08fda293e 100644 --- a/cmd/rpcdaemon/commands/erigon_receipts.go +++ b/cmd/rpcdaemon/commands/erigon_receipts.go @@ -52,13 +52,13 @@ func (api *ErigonImpl) GetLogsByHash(ctx context.Context, hash common.Hash) ([][ } // GetLogs implements eth_getLogs. Returns an array of logs matching a given filter object. -func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) { +func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) (types.ErigonLogs, error) { var begin, end uint64 - logs := []*types.Log{} + erigonLogs := types.ErigonLogs{} tx, beginErr := api.db.BeginRo(ctx) if beginErr != nil { - return logs, beginErr + return erigonLogs, beginErr } defer tx.Rollback() @@ -128,7 +128,7 @@ func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) } if blockNumbers.GetCardinality() == 0 { - return logs, nil + return erigonLogs, nil } iter := blockNumbers.Iterator() @@ -163,7 +163,7 @@ func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) return nil }) if err != nil { - return logs, err + return erigonLogs, err } if len(blockLogs) == 0 { continue @@ -190,16 +190,17 @@ func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) if body == nil { return nil, fmt.Errorf("block not found %d", blockNumber) } - for _, log := range blockLogs { - log.Timestamp = timestamp + for i, log := range blockLogs { log.BlockNumber = blockNumber log.BlockHash = blockHash log.TxHash = body.Transactions[log.TxIndex].Hash() + + erigonLogs[i].Log = *log + erigonLogs[i].Timestamp = timestamp } - logs = append(logs, blockLogs...) } - return logs, nil + return erigonLogs, nil } // GetLogsByNumber implements erigon_getLogsByHash. Returns all the logs that appear in a block given the block's hash. diff --git a/cmd/rpcdaemon/commands/eth_api.go b/cmd/rpcdaemon/commands/eth_api.go index c997fc75b..d3682c59e 100644 --- a/cmd/rpcdaemon/commands/eth_api.go +++ b/cmd/rpcdaemon/commands/eth_api.go @@ -46,7 +46,7 @@ type EthAPI interface { // Receipt related (see ./eth_receipts.go) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) - GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) ([]*types.Log, error) + GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) (types.Logs, error) GetBlockReceipts(ctx context.Context, number rpc.BlockNumber) ([]map[string]interface{}, error) // Uncle related (see ./eth_uncles.go) diff --git a/cmd/rpcdaemon/commands/eth_receipts.go b/cmd/rpcdaemon/commands/eth_receipts.go index 8bc3c0475..97646f805 100644 --- a/cmd/rpcdaemon/commands/eth_receipts.go +++ b/cmd/rpcdaemon/commands/eth_receipts.go @@ -72,9 +72,9 @@ func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *para } // GetLogs implements eth_getLogs. Returns an array of logs matching a given filter object. -func (api *APIImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) { +func (api *APIImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) (types.Logs, error) { var begin, end uint64 - logs := []*types.Log{} + logs := types.Logs{} tx, beginErr := api.db.BeginRo(ctx) if beginErr != nil { diff --git a/cmd/rpcdaemon22/commands/erigon_api.go b/cmd/rpcdaemon22/commands/erigon_api.go index 9af7a08fe..d6fd93699 100644 --- a/cmd/rpcdaemon22/commands/erigon_api.go +++ b/cmd/rpcdaemon22/commands/erigon_api.go @@ -28,7 +28,7 @@ type ErigonAPI interface { // Receipt related (see ./erigon_receipts.go) GetLogsByHash(ctx context.Context, hash common.Hash) ([][]*types.Log, error) //GetLogsByNumber(ctx context.Context, number rpc.BlockNumber) ([][]*types.Log, error) - GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) ([]*types.Log, error) + GetLogs(ctx context.Context, crit ethFilters.FilterCriteria) (types.ErigonLogs, error) // WatchTheBurn / reward related (see ./erigon_issuance.go) WatchTheBurn(ctx context.Context, blockNr rpc.BlockNumber) (Issuance, error) diff --git a/cmd/rpcdaemon22/commands/erigon_receipts.go b/cmd/rpcdaemon22/commands/erigon_receipts.go index 7f721df6a..9534ccee9 100644 --- a/cmd/rpcdaemon22/commands/erigon_receipts.go +++ b/cmd/rpcdaemon22/commands/erigon_receipts.go @@ -53,14 +53,14 @@ func (api *ErigonImpl) GetLogsByHash(ctx context.Context, hash common.Hash) ([][ } // GetLogs implements erigon_getLogs. Return an array of logs that matches the filter conditions -func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) { +func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) (types.ErigonLogs, error) { start := time.Now() var begin, end uint64 - logs := []*types.Log{} + erigonLogs := types.ErigonLogs{} tx, beginErr := api.db.BeginRo(ctx) if beginErr != nil { - return logs, beginErr + return erigonLogs, beginErr } defer tx.Rollback() @@ -141,7 +141,7 @@ func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) } if txNumbers.GetCardinality() == 0 { - return logs, nil + return erigonLogs, nil } var lastBlockNum uint64 var lastBlockHash common.Hash @@ -197,18 +197,19 @@ func (api *ErigonImpl) GetLogs(ctx context.Context, crit filters.FilterCriteria) return nil, err } filtered := filterLogs(ibs.GetLogs(txHash), crit.Addresses, crit.Topics) - for _, log := range filtered { + for i, log := range filtered { log.BlockNumber = blockNum - log.Timestamp = timestamp log.BlockHash = lastBlockHash log.TxHash = txHash log.Index = 0 + + erigonLogs[i].Log = *log + erigonLogs[i].Timestamp = timestamp } - logs = append(logs, filtered...) } stats := api._agg.GetAndResetStats() log.Info("Finished", "duration", time.Since(start), "history queries", stats.HistoryQueries, "ef search duration", stats.EfSearchTime) - return logs, nil + return erigonLogs, nil } // GetLogsByNumber implements erigon_getLogsByHash. Returns all the logs that appear in a block given the block's hash. diff --git a/core/types/gen_erigon_log_json.go b/core/types/gen_erigon_log_json.go new file mode 100644 index 000000000..dfe9ee3ea --- /dev/null +++ b/core/types/gen_erigon_log_json.go @@ -0,0 +1,114 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" +) + +var _ = (*logMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (l ErigonLog) MarshalJSON() ([]byte, error) { + type Log struct { + Address common.Address `json:"address" gencodec:"required"` + Topics []common.Hash `json:"topics" gencodec:"required"` + Data hexutil.Bytes `json:"data" gencodec:"required"` + BlockNumber hexutil.Uint64 `json:"blockNumber"` + TxHash common.Hash `json:"transactionHash" gencodec:"required"` + TxIndex hexutil.Uint `json:"transactionIndex"` + BlockHash common.Hash `json:"blockHash"` + Index hexutil.Uint `json:"logIndex"` + Removed bool `json:"removed"` + } + + type ErigonLog struct { + Log Log `json:"log" gencoded:"required"` + Timestamp hexutil.Uint64 `json:"timestamp"` + } + + var enc Log + enc.Address = l.Log.Address + enc.Topics = l.Log.Topics + enc.Data = l.Log.Data + enc.BlockNumber = hexutil.Uint64(l.Log.BlockNumber) + enc.TxHash = l.Log.TxHash + enc.TxIndex = hexutil.Uint(l.Log.TxIndex) + enc.BlockHash = l.Log.BlockHash + enc.Index = hexutil.Uint(l.Log.Index) + enc.Removed = l.Log.Removed + + var encodedErigonLog ErigonLog + encodedErigonLog.Log = enc + encodedErigonLog.Timestamp = hexutil.Uint64(l.Timestamp) + + + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (l *ErigonLog) UnmarshalJSON(input []byte) error { + type Log struct { + Address *common.Address `json:"address" gencodec:"required"` + Topics []common.Hash `json:"topics" gencodec:"required"` + Data *hexutil.Bytes `json:"data" gencodec:"required"` + BlockNumber *hexutil.Uint64 `json:"blockNumber"` + TxHash *common.Hash `json:"transactionHash" gencodec:"required"` + TxIndex *hexutil.Uint `json:"transactionIndex"` + BlockHash *common.Hash `json:"blockHash"` + Index *hexutil.Uint `json:"logIndex"` + Removed *bool `json:"removed"` + } + + type ErigonLog struct { + Log Log `json:"log" gencodec:"required"` + Timestamp *hexutil.Uint64 `json:"timestamp"` + } + + var dec ErigonLog + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Log.Address == nil { + return errors.New("missing required field 'address' for Log") + } + l.Log.Address = *dec.Log.Address + if dec.Log.Topics == nil { + return errors.New("missing required field 'topics' for Log") + } + l.Log.Topics = dec.Log.Topics + if dec.Log.Data == nil { + return errors.New("missing required field 'data' for Log") + } + l.Log.Data = *dec.Log.Data + if dec.Log.BlockNumber != nil { + l.Log.BlockNumber = uint64(*dec.Log.BlockNumber) + } + + if dec.Log.TxHash == nil { + return errors.New("missing required field 'transactionHash' for Log") + } + l.Log.TxHash = *dec.Log.TxHash + if dec.Log.TxIndex != nil { + l.Log.TxIndex = uint(*dec.Log.TxIndex) + } + if dec.Log.BlockHash != nil { + l.Log.BlockHash = *dec.Log.BlockHash + } + if dec.Log.Index != nil { + l.Log.Index = uint(*dec.Log.Index) + } + if dec.Log.Removed != nil { + l.Log.Removed = *dec.Log.Removed + } + + if dec.Timestamp != nil { + l.Timestamp = uint64(*dec.Timestamp) + } + + return nil +} diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go index f9382a54e..236e7aecc 100644 --- a/core/types/gen_log_json.go +++ b/core/types/gen_log_json.go @@ -19,7 +19,6 @@ func (l Log) MarshalJSON() ([]byte, error) { Topics []common.Hash `json:"topics" gencodec:"required"` Data hexutil.Bytes `json:"data" gencodec:"required"` BlockNumber hexutil.Uint64 `json:"blockNumber"` - Timestamp hexutil.Uint64 `json:"timestamp"` TxHash common.Hash `json:"transactionHash" gencodec:"required"` TxIndex hexutil.Uint `json:"transactionIndex"` BlockHash common.Hash `json:"blockHash"` @@ -31,7 +30,6 @@ func (l Log) MarshalJSON() ([]byte, error) { enc.Topics = l.Topics enc.Data = l.Data enc.BlockNumber = hexutil.Uint64(l.BlockNumber) - enc.Timestamp = hexutil.Uint64(l.Timestamp) enc.TxHash = l.TxHash enc.TxIndex = hexutil.Uint(l.TxIndex) enc.BlockHash = l.BlockHash @@ -47,7 +45,6 @@ func (l *Log) UnmarshalJSON(input []byte) error { Topics []common.Hash `json:"topics" gencodec:"required"` Data *hexutil.Bytes `json:"data" gencodec:"required"` BlockNumber *hexutil.Uint64 `json:"blockNumber"` - Timestamp *hexutil.Uint64 `json:"timestamp"` TxHash *common.Hash `json:"transactionHash" gencodec:"required"` TxIndex *hexutil.Uint `json:"transactionIndex"` BlockHash *common.Hash `json:"blockHash"` @@ -73,9 +70,7 @@ func (l *Log) UnmarshalJSON(input []byte) error { if dec.BlockNumber != nil { l.BlockNumber = uint64(*dec.BlockNumber) } - if dec.Timestamp != nil { - l.Timestamp = uint64(*dec.Timestamp) - } + if dec.TxHash == nil { return errors.New("missing required field 'transactionHash' for Log") } diff --git a/core/types/log.go b/core/types/log.go index 67e8f330e..ac2e4633e 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -42,7 +42,6 @@ type Log struct { // block in which the transaction was included BlockNumber uint64 `json:"blockNumber" codec:"-"` - Timestamp uint64 `json:"timestamp" codec:"-"` // hash of the transaction TxHash common.Hash `json:"transactionHash" gencodec:"required" codec:"-"` // index of the transaction in the block @@ -57,6 +56,13 @@ type Log struct { Removed bool `json:"removed" codec:"-"` } +type ErigonLog struct { + Log Log `json:"log"` + Timestamp uint64 `json:"timestamp" codec:"-"` +} + +type ErigonLogs []*ErigonLog + type Logs []*Log type logMarshaling struct { diff --git a/core/types/log_test.go b/core/types/log_test.go index 6d913518b..f16e9bead 100644 --- a/core/types/log_test.go +++ b/core/types/log_test.go @@ -38,7 +38,6 @@ var unmarshalLogTests = map[string]struct { Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"), BlockNumber: 2019236, - Timestamp: 1470446906, Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"), Index: 2, TxIndex: 3, @@ -49,13 +48,13 @@ var unmarshalLogTests = map[string]struct { }, }, }, + "empty data": { input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","timestamp":"0x57a53d3a","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, want: &Log{ Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"), BlockNumber: 2019236, - Timestamp: 1470446906, Data: []byte{}, Index: 2, TxIndex: 3, @@ -72,11 +71,11 @@ var unmarshalLogTests = map[string]struct { Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), BlockHash: common.Hash{}, BlockNumber: 0, - Timestamp: 0, - Data: []byte{}, - Index: 0, - TxIndex: 3, - TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), + + Data: []byte{}, + Index: 0, + TxIndex: 3, + TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), Topics: []common.Hash{ common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), }, @@ -88,11 +87,11 @@ var unmarshalLogTests = map[string]struct { Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"), BlockNumber: 2019236, - Timestamp: 1470446906, - Data: []byte{}, - Index: 2, - TxIndex: 3, - TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), + + Data: []byte{}, + Index: 2, + TxIndex: 3, + TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), Topics: []common.Hash{ common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), },