Skip to content

Commit

Permalink
fix tx index provided in the tx log responses (#3303)
Browse files Browse the repository at this point in the history
  • Loading branch information
tclemos committed Feb 22, 2024
1 parent 49e837a commit 4193151
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 6 deletions.
6 changes: 4 additions & 2 deletions state/pgstatestorage/pgstatestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,11 @@ func (p *PostgresStorage) GetStateRootByBatchNumber(ctx context.Context, batchNu
// GetLogsByBlockNumber get all the logs from a specific block ordered by log index
func (p *PostgresStorage) GetLogsByBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) ([]*types.Log, error) {
const query = `
SELECT t.l2_block_num, b.block_hash, l.tx_hash, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3
SELECT t.l2_block_num, b.block_hash, l.tx_hash, r.tx_index, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3
FROM state.log l
INNER JOIN state.transaction t ON t.hash = l.tx_hash
INNER JOIN state.l2block b ON b.block_num = t.l2_block_num
INNER JOIN state.receipt r ON r.tx_hash = t.hash
WHERE b.block_num = $1
ORDER BY l.log_index ASC`

Expand All @@ -142,11 +143,12 @@ func (p *PostgresStorage) GetLogsByBlockNumber(ctx context.Context, blockNumber
func (p *PostgresStorage) GetLogs(ctx context.Context, fromBlock uint64, toBlock uint64, addresses []common.Address, topics [][]common.Hash, blockHash *common.Hash, since *time.Time, dbTx pgx.Tx) ([]*types.Log, error) {
// query parts
const queryCount = `SELECT count(*) `
const querySelect = `SELECT t.l2_block_num, b.block_hash, l.tx_hash, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3 `
const querySelect = `SELECT t.l2_block_num, b.block_hash, l.tx_hash, r.tx_index, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3 `

const queryBody = `FROM state.log l
INNER JOIN state.transaction t ON t.hash = l.tx_hash
INNER JOIN state.l2block b ON b.block_num = t.l2_block_num
INNER JOIN state.receipt r ON r.tx_hash = t.hash
WHERE (l.address = any($1) OR $1 IS NULL)
AND (l.topic0 = any($2) OR $2 IS NULL)
AND (l.topic1 = any($3) OR $3 IS NULL)
Expand Down
8 changes: 5 additions & 3 deletions state/pgstatestorage/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,11 @@ func (p *PostgresStorage) getTransactionLogs(ctx context.Context, transactionHas
q := p.getExecQuerier(dbTx)

const getTransactionLogsSQL = `
SELECT t.l2_block_num, b.block_hash, l.tx_hash, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3
SELECT t.l2_block_num, b.block_hash, l.tx_hash, r.tx_index, l.log_index, l.address, l.data, l.topic0, l.topic1, l.topic2, l.topic3
FROM state.log l
INNER JOIN state.transaction t ON t.hash = l.tx_hash
INNER JOIN state.l2block b ON b.block_num = t.l2_block_num
INNER JOIN state.receipt r ON r.tx_hash = t.hash
WHERE t.hash = $1
ORDER BY l.log_index ASC`
rows, err := q.Query(ctx, getTransactionLogsSQL, transactionHash.String())
Expand All @@ -391,10 +392,11 @@ func scanLogs(rows pgx.Rows) ([]*types.Log, error) {
}

var log types.Log
var txIndex uint
var blockHash, txHash, logAddress, logData string
var topic0, topic1, topic2, topic3 *string

err := rows.Scan(&log.BlockNumber, &blockHash, &txHash, &log.Index,
err := rows.Scan(&log.BlockNumber, &blockHash, &txHash, &txIndex, &log.Index,
&logAddress, &logData, &topic0, &topic1, &topic2, &topic3)
if err != nil {
return nil, err
Expand All @@ -403,7 +405,7 @@ func scanLogs(rows pgx.Rows) ([]*types.Log, error) {
log.BlockHash = common.HexToHash(blockHash)
log.TxHash = common.HexToHash(txHash)
log.Address = common.HexToAddress(logAddress)
log.TxIndex = uint(0)
log.TxIndex = txIndex
log.Data, err = hex.DecodeHex(logData)
if err != nil {
return nil, err
Expand Down
147 changes: 146 additions & 1 deletion test/e2e/sc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"math/big"
"testing"
"time"

"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state"
"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Counter"
"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/EmitLog2"
"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/FailureTest"
Expand Down Expand Up @@ -265,8 +267,9 @@ func TestEmitLog2(t *testing.T) {
log0 := getLogByIndex(0, logs)
assert.Equal(t, 0, len(log0.Topics))

_, err = sc.ParseLog(getLogByIndex(1, logs))
logWithoutParameters, err := sc.ParseLog(getLogByIndex(1, logs))
require.NoError(t, err)
assert.Equal(t, 1, len(logWithoutParameters.Raw.Topics))

logA, err := sc.ParseLogA(getLogByIndex(2, logs))
require.NoError(t, err)
Expand Down Expand Up @@ -329,6 +332,148 @@ func TestEmitLog2(t *testing.T) {
}
}

func TestLogTxIndex(t *testing.T) {
if testing.Short() {
t.Skip()
}

var err error
err = operations.Teardown()
require.NoError(t, err)

defer func() { require.NoError(t, operations.Teardown()) }()

ctx := context.Background()
opsCfg := operations.GetDefaultOperationsConfig()
opsMan, err := operations.NewManager(ctx, opsCfg)
require.NoError(t, err)
err = opsMan.Setup()
require.NoError(t, err)

assertTxHashAndIndex := func(t *testing.T, log types.Log, tx *types.Transaction, receipt *types.Receipt) {
assert.Equal(t, tx.Hash().String(), log.TxHash.String())
assert.Equal(t, receipt.TxHash.String(), log.TxHash.String())
assert.Equal(t, receipt.TransactionIndex, log.TxIndex)
}

for _, network := range networks {
log.Debugf(network.Name)
client := operations.MustGetClient(network.URL)
wsClient := operations.MustGetClient(network.WebSocketURL)
auth := operations.MustGetAuth(network.PrivateKey, network.ChainID)

// deploy sc
scAddr, scTx, sc, err := EmitLog2.DeployEmitLog2(auth, client)
require.NoError(t, err)

logTx(scTx)
err = operations.WaitTxToBeMined(ctx, client, scTx, operations.DefaultTimeoutTxToBeMined)
require.NoError(t, err)

if network.Name == "Local L2" {
// stops sequencer
err = operations.StopComponent("seq")
require.NoError(t, err)
}

logsFromSubscription := make(chan types.Log)
query := ethereum.FilterQuery{Addresses: []common.Address{scAddr}}
sub, err := wsClient.SubscribeFilterLogs(context.Background(), query, logsFromSubscription)
require.NoError(t, err)

// send transfer
gasPrice, err := client.SuggestGasPrice(ctx)
require.NoError(t, err)
nonce, err := client.PendingNonceAt(ctx, auth.From)
require.NoError(t, err)
tx := types.NewTx(&types.LegacyTx{
To: state.Ptr(common.HexToAddress("0x1")),
Gas: 30000,
GasPrice: gasPrice,
Value: big.NewInt(1000),
Nonce: nonce,
})
signedTx, err := auth.Signer(auth.From, tx)
require.NoError(t, err)
err = client.SendTransaction(ctx, signedTx)
require.NoError(t, err)

// send log tx
auth.Nonce = big.NewInt(0).SetUint64(nonce + 1)
scCallTx, err := sc.EmitLogs(auth)
require.NoError(t, err)
logTx(scCallTx)

time.Sleep(time.Second)

if network.Name == "Local L2" {
// starts sequencer and wait log tx to get mined
err = operations.StartComponent("seq", func() (done bool, err error) {
err = operations.WaitTxToBeMined(ctx, client, scCallTx, operations.DefaultTimeoutTxToBeMined)
return true, err
})
require.NoError(t, err)
} else {
err = operations.WaitTxToBeMined(ctx, client, scCallTx, operations.DefaultTimeoutTxToBeMined)
require.NoError(t, err)
}

scCallTxReceipt, err := client.TransactionReceipt(ctx, scCallTx.Hash())
require.NoError(t, err)

if network.Name == "Local L2" {
assert.Equal(t, uint(1), scCallTxReceipt.TransactionIndex)
}

// validate logs from filterLogs
filterBlock := scCallTxReceipt.BlockNumber
logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{
FromBlock: filterBlock, ToBlock: filterBlock,
Addresses: []common.Address{scAddr},
})
require.NoError(t, err)

assert.Equal(t, 4, len(logs))
for i := range logs {
l := getLogByIndex(i, logs)
assertTxHashAndIndex(t, l, scCallTx, scCallTxReceipt)
}

// validate logs from receipt
logs = make([]types.Log, len(scCallTxReceipt.Logs))
for i, log := range scCallTxReceipt.Logs {
logs[i] = *log
}

assert.Equal(t, 4, len(logs))
for i := range logs {
l := getLogByIndex(i, logs)
assertTxHashAndIndex(t, l, scCallTx, scCallTxReceipt)
}

// validate logs by subscription
logs = []types.Log{}
out:
for {
select {
case err := <-sub.Err():
require.NoError(t, err)
case vLog, closed := <-logsFromSubscription:
logs = append(logs, vLog)
if len(logs) == 4 && closed {
break out
}
}
}

assert.Equal(t, 4, len(logs))
for i := range logs {
l := getLogByIndex(i, logs)
assertTxHashAndIndex(t, l, scCallTx, scCallTxReceipt)
}
}
}

func getLogByIndex(index int, logs []types.Log) types.Log {
for _, log := range logs {
if int(log.Index) == index {
Expand Down

0 comments on commit 4193151

Please sign in to comment.