From fa2be0cee111cc9dd078a68ce955783bbc7b43ed Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 16:55:07 +0800 Subject: [PATCH 01/11] add zkevm_getBatchSealTime --- jsonrpc/endpoints_zkevm_xlayer.go | 25 +++++++++++++++++++++++++ jsonrpc/types/interfaces.go | 3 +++ state/interfaces.go | 1 + state/pgstatestorage/l2block_xlayer.go | 21 +++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 jsonrpc/endpoints_zkevm_xlayer.go create mode 100644 state/pgstatestorage/l2block_xlayer.go diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go new file mode 100644 index 0000000000..c786ccda80 --- /dev/null +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -0,0 +1,25 @@ +package jsonrpc + +import ( + "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "fmt" + "github.com/jackc/pgx/v4" + "context" +) + +// GetBatchSealTime returns the seal time +func (z *ZKEVMEndpoints) GetBatchSealTime(batchNumber types.BatchNumber) (interface{}, types.Error) { + return z.txMan.NewDbTxScope(z.state, func(ctx context.Context, dbTx pgx.Tx) (interface{}, types.Error) { + var err error + batchNumber, rpcErr := batchNumber.GetNumericBatchNumber(ctx, z.state, z.etherman, dbTx) + if rpcErr != nil { + return nil, rpcErr + } + + sealTime, err := z.state.GetLastL2BlockCreateTimeBatchNumber(ctx, batchNumber, dbTx) + if err != nil { + return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block create time from state by batch number %v", batchNumber), err, true) + } + return sealTime.Unix(), nil + }) +} diff --git a/jsonrpc/types/interfaces.go b/jsonrpc/types/interfaces.go index 54c0561c98..2dd441ae90 100644 --- a/jsonrpc/types/interfaces.go +++ b/jsonrpc/types/interfaces.go @@ -83,6 +83,9 @@ type StateInterface interface { GetLatestBatchGlobalExitRoot(ctx context.Context, dbTx pgx.Tx) (common.Hash, error) GetL2TxHashByTxHash(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (*common.Hash, error) PreProcessUnsignedTransaction(ctx context.Context, tx *types.Transaction, sender common.Address, l2BlockNumber *uint64, dbTx pgx.Tx) (*state.ProcessBatchResponse, error) + + // GetLastL2BlockCreateTimeBatchNumber gets the last l2 block create time in a batch by batch number X Layer handler + GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) } // EthermanInterface provides integration with L1 diff --git a/state/interfaces.go b/state/interfaces.go index f412a9902d..c8b0304880 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -167,4 +167,5 @@ type storage interface { // GetBatchL2DataByNumber is XLayer method GetBatchL2DataByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]byte, error) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers []uint64, dbTx pgx.Tx) (map[uint64][]byte, error) + GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) } diff --git a/state/pgstatestorage/l2block_xlayer.go b/state/pgstatestorage/l2block_xlayer.go new file mode 100644 index 0000000000..3b3d6c9587 --- /dev/null +++ b/state/pgstatestorage/l2block_xlayer.go @@ -0,0 +1,21 @@ +package pgstatestorage + +import ( + "github.com/jackc/pgx/v4" + "context" + "time" +) + +// GetLastL2BlockCreateTimeBatchNumber gets the last l2 block create time in a batch by batch number +func (p *PostgresStorage) GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) { + const query = "SELECT created_at FROM state.l2block b WHERE batch_num = $1 ORDER BY b.block_num DESC LIMIT 1" + + var createdAt time.Time + q := p.getExecQuerier(dbTx) + err := q.QueryRow(ctx, query, batchNumber).Scan(&createdAt) + if err != nil { + return nil, err + } + + return &createdAt, nil +} From b540b5ceb83cf118a443115d6390c5e5c6b30413 Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 17:47:24 +0800 Subject: [PATCH 02/11] use block time instead of create time --- jsonrpc/endpoints_zkevm_xlayer.go | 6 ++++-- jsonrpc/types/interfaces.go | 4 ++-- state/interfaces.go | 2 +- state/pgstatestorage/l2block_xlayer.go | 20 ++++++++++++-------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go index c786ccda80..7a1327846f 100644 --- a/jsonrpc/endpoints_zkevm_xlayer.go +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/jackc/pgx/v4" "context" + "github.com/0xPolygonHermez/zkevm-node/hex" ) // GetBatchSealTime returns the seal time @@ -16,10 +17,11 @@ func (z *ZKEVMEndpoints) GetBatchSealTime(batchNumber types.BatchNumber) (interf return nil, rpcErr } - sealTime, err := z.state.GetLastL2BlockCreateTimeBatchNumber(ctx, batchNumber, dbTx) + sealTime, err := z.state.GetLastL2BlockTimeByBatchNumber(ctx, batchNumber, dbTx) if err != nil { return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block create time from state by batch number %v", batchNumber), err, true) } - return sealTime.Unix(), nil + + return hex.EncodeUint64(sealTime), nil }) } diff --git a/jsonrpc/types/interfaces.go b/jsonrpc/types/interfaces.go index 2dd441ae90..c09dcdc0ce 100644 --- a/jsonrpc/types/interfaces.go +++ b/jsonrpc/types/interfaces.go @@ -84,8 +84,8 @@ type StateInterface interface { GetL2TxHashByTxHash(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (*common.Hash, error) PreProcessUnsignedTransaction(ctx context.Context, tx *types.Transaction, sender common.Address, l2BlockNumber *uint64, dbTx pgx.Tx) (*state.ProcessBatchResponse, error) - // GetLastL2BlockCreateTimeBatchNumber gets the last l2 block create time in a batch by batch number X Layer handler - GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) + // GetLastL2BlockTimeByBatchNumber gets the last l2 block time in a batch by batch number X Layer handler + GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) } // EthermanInterface provides integration with L1 diff --git a/state/interfaces.go b/state/interfaces.go index c8b0304880..e6e08b693b 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -167,5 +167,5 @@ type storage interface { // GetBatchL2DataByNumber is XLayer method GetBatchL2DataByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]byte, error) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers []uint64, dbTx pgx.Tx) (map[uint64][]byte, error) - GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) + GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) } diff --git a/state/pgstatestorage/l2block_xlayer.go b/state/pgstatestorage/l2block_xlayer.go index 3b3d6c9587..f777af4977 100644 --- a/state/pgstatestorage/l2block_xlayer.go +++ b/state/pgstatestorage/l2block_xlayer.go @@ -3,19 +3,23 @@ package pgstatestorage import ( "github.com/jackc/pgx/v4" "context" - "time" + "github.com/0xPolygonHermez/zkevm-node/state" + "errors" ) -// GetLastL2BlockCreateTimeBatchNumber gets the last l2 block create time in a batch by batch number -func (p *PostgresStorage) GetLastL2BlockCreateTimeBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, error) { +// GetLastL2BlockTimeByBatchNumber gets the last l2 block time in a batch by batch number +func (p *PostgresStorage) GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) { const query = "SELECT created_at FROM state.l2block b WHERE batch_num = $1 ORDER BY b.block_num DESC LIMIT 1" - var createdAt time.Time + header := &state.L2Header{} q := p.getExecQuerier(dbTx) - err := q.QueryRow(ctx, query, batchNumber).Scan(&createdAt) - if err != nil { - return nil, err + err := q.QueryRow(ctx, query, batchNumber).Scan(&header) + + if errors.Is(err, pgx.ErrNoRows) { + return 0, state.ErrNotFound + } else if err != nil { + return 0, err } - return &createdAt, nil + return header.Time, nil } From c109db2660363c0c37a7bd3f7d5f021c3e2aed0b Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 18:01:06 +0800 Subject: [PATCH 03/11] fix sql error and fix comment --- jsonrpc/endpoints_zkevm_xlayer.go | 2 +- state/pgstatestorage/l2block_xlayer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go index 7a1327846f..912c06c36f 100644 --- a/jsonrpc/endpoints_zkevm_xlayer.go +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -19,7 +19,7 @@ func (z *ZKEVMEndpoints) GetBatchSealTime(batchNumber types.BatchNumber) (interf sealTime, err := z.state.GetLastL2BlockTimeByBatchNumber(ctx, batchNumber, dbTx) if err != nil { - return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block create time from state by batch number %v", batchNumber), err, true) + return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block time from state by batch number %v", batchNumber), err, true) } return hex.EncodeUint64(sealTime), nil diff --git a/state/pgstatestorage/l2block_xlayer.go b/state/pgstatestorage/l2block_xlayer.go index f777af4977..b6d6468612 100644 --- a/state/pgstatestorage/l2block_xlayer.go +++ b/state/pgstatestorage/l2block_xlayer.go @@ -9,7 +9,7 @@ import ( // GetLastL2BlockTimeByBatchNumber gets the last l2 block time in a batch by batch number func (p *PostgresStorage) GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) { - const query = "SELECT created_at FROM state.l2block b WHERE batch_num = $1 ORDER BY b.block_num DESC LIMIT 1" + const query = "SELECT header FROM state.l2block b WHERE batch_num = $1 ORDER BY b.block_num DESC LIMIT 1" header := &state.L2Header{} q := p.getExecQuerier(dbTx) From 4c1d262690551d69c1395b1efe28fd9b357eea2c Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 18:26:56 +0800 Subject: [PATCH 04/11] add the mock state xlayer --- jsonrpc/mocks/mock_state_xlayer.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/jsonrpc/mocks/mock_state_xlayer.go b/jsonrpc/mocks/mock_state_xlayer.go index e01d802c7e..f06421a831 100644 --- a/jsonrpc/mocks/mock_state_xlayer.go +++ b/jsonrpc/mocks/mock_state_xlayer.go @@ -86,3 +86,26 @@ func (_m *StateMock) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers [ return r0, r1 } + +func (_m *StateMock)GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) { + ret := _m.Called(ctx, batchNumber, dbTx) + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (uint64, error)); ok { + return rf(ctx, batchNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) uint64); ok { + r0 = rf(ctx, batchNumber, dbTx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, batchNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} From bac6ea1187b9fa01619bfe5f8521836a1dcce9ce Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 18:32:55 +0800 Subject: [PATCH 05/11] storageMock add GetLastL2BlockTimeByBatchNumber --- state/mocks/mock_storage_xlayer.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/state/mocks/mock_storage_xlayer.go b/state/mocks/mock_storage_xlayer.go index 99a912c025..929f096a04 100644 --- a/state/mocks/mock_storage_xlayer.go +++ b/state/mocks/mock_storage_xlayer.go @@ -8,10 +8,14 @@ import ( pgx "github.com/jackc/pgx/v4" ) -func (_m *StorageMock) GetBatchL2DataByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]byte, error){ +func (_m *StorageMock) GetBatchL2DataByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]byte, error) { return nil, nil } -func (_m *StorageMock) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers []uint64, dbTx pgx.Tx) (map[uint64][]byte, error){ +func (_m *StorageMock) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers []uint64, dbTx pgx.Tx) (map[uint64][]byte, error) { return nil, nil -} \ No newline at end of file +} + +func (_m *StorageMock) GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) { + return 0, nil +} From 11fc0a39a30723fe34a6eb2ecbd2ae31e4f8680d Mon Sep 17 00:00:00 2001 From: zhangkai Date: Wed, 19 Jun 2024 18:44:34 +0800 Subject: [PATCH 06/11] format imports --- jsonrpc/endpoints_zkevm_xlayer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go index 912c06c36f..d0dedeb556 100644 --- a/jsonrpc/endpoints_zkevm_xlayer.go +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -1,11 +1,12 @@ package jsonrpc import ( - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" - "fmt" - "github.com/jackc/pgx/v4" "context" + "fmt" + "github.com/0xPolygonHermez/zkevm-node/hex" + "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "github.com/jackc/pgx/v4" ) // GetBatchSealTime returns the seal time From 05e7e0d0e6a8c288e48aa5818d8a53486ab9d5da Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 20 Jun 2024 11:53:24 +0800 Subject: [PATCH 07/11] our batch number should closed --- state/pgstatestorage/l2block_xlayer.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/state/pgstatestorage/l2block_xlayer.go b/state/pgstatestorage/l2block_xlayer.go index b6d6468612..9094354b2f 100644 --- a/state/pgstatestorage/l2block_xlayer.go +++ b/state/pgstatestorage/l2block_xlayer.go @@ -1,14 +1,23 @@ package pgstatestorage import ( - "github.com/jackc/pgx/v4" "context" - "github.com/0xPolygonHermez/zkevm-node/state" "errors" + "fmt" + + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/jackc/pgx/v4" ) // GetLastL2BlockTimeByBatchNumber gets the last l2 block time in a batch by batch number func (p *PostgresStorage) GetLastL2BlockTimeByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (uint64, error) { + lastClosedBatchNumber, err := p.GetLastBatchNumber(ctx, dbTx) + if err != nil { + return 0, err + } + if batchNumber > lastClosedBatchNumber { + return 0, fmt.Errorf("%w. got %d, last batch should be %d", state.ErrUnexpectedBatch, batchNumber, lastClosedBatchNumber) + } const query = "SELECT header FROM state.l2block b WHERE batch_num = $1 ORDER BY b.block_num DESC LIMIT 1" header := &state.L2Header{} From 27d985117221e83eef1b48a6aad38f581999ff03 Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 20 Jun 2024 11:56:37 +0800 Subject: [PATCH 08/11] fix compile error --- state/pgstatestorage/l2block_xlayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/pgstatestorage/l2block_xlayer.go b/state/pgstatestorage/l2block_xlayer.go index 9094354b2f..a03a79bb01 100644 --- a/state/pgstatestorage/l2block_xlayer.go +++ b/state/pgstatestorage/l2block_xlayer.go @@ -22,7 +22,7 @@ func (p *PostgresStorage) GetLastL2BlockTimeByBatchNumber(ctx context.Context, b header := &state.L2Header{} q := p.getExecQuerier(dbTx) - err := q.QueryRow(ctx, query, batchNumber).Scan(&header) + err = q.QueryRow(ctx, query, batchNumber).Scan(&header) if errors.Is(err, pgx.ErrNoRows) { return 0, state.ErrNotFound From 67ef97497e00dd697c946abda9ddf068e9275a0e Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 20 Jun 2024 12:08:28 +0800 Subject: [PATCH 09/11] return error msg, do not record it --- jsonrpc/endpoints_zkevm_xlayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go index d0dedeb556..972aeb8a02 100644 --- a/jsonrpc/endpoints_zkevm_xlayer.go +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -20,7 +20,7 @@ func (z *ZKEVMEndpoints) GetBatchSealTime(batchNumber types.BatchNumber) (interf sealTime, err := z.state.GetLastL2BlockTimeByBatchNumber(ctx, batchNumber, dbTx) if err != nil { - return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block time from state by batch number %v", batchNumber), err, true) + return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block time from state batch number %v, error: %v", batchNumber, err), nil, false) } return hex.EncodeUint64(sealTime), nil From 21040db695730ff7c5975f969e79ab08dfd8c984 Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 20 Jun 2024 15:07:27 +0800 Subject: [PATCH 10/11] add doc --- jsonrpc/endpoints_zkevm.openrpc.json | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/jsonrpc/endpoints_zkevm.openrpc.json b/jsonrpc/endpoints_zkevm.openrpc.json index 5875d2fc76..21f059caba 100644 --- a/jsonrpc/endpoints_zkevm.openrpc.json +++ b/jsonrpc/endpoints_zkevm.openrpc.json @@ -177,8 +177,7 @@ "result": { "$ref": "#/components/contentDescriptors/BatchDataResult" } - }, - { + }, { "name": "zkevm_getBatchByNumber", "summary": "Gets a batch for a given number", "params": [ @@ -483,6 +482,22 @@ "$ref": "#/components/schemas/Integer" } } + }, + { + "name": "zkevm_getBatchSealTime", + "summary": "Get Batch seal time", + "params": [ + { + "$ref": "#/components/contentDescriptors/BatchNumber" + } + ], + "result": { + "name": "result", + "description": "The batch seal time", + "schema": { + "$ref": "#/components/schemas/Timestamp" + } + } } ], "components": { @@ -1470,6 +1485,11 @@ "$ref": "#/components/schemas/Integer" } } + }, + "Timestamp": { + "title": "timestamp", + "type": "string", + "description": "The unix timestamp of the batch" } } } From b1cc891b3fad50ae6892cf65268e2d54684d03ca Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 20 Jun 2024 15:16:25 +0800 Subject: [PATCH 11/11] beautify error message --- jsonrpc/endpoints_zkevm_xlayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonrpc/endpoints_zkevm_xlayer.go b/jsonrpc/endpoints_zkevm_xlayer.go index 972aeb8a02..aa19b3cfe9 100644 --- a/jsonrpc/endpoints_zkevm_xlayer.go +++ b/jsonrpc/endpoints_zkevm_xlayer.go @@ -20,7 +20,7 @@ func (z *ZKEVMEndpoints) GetBatchSealTime(batchNumber types.BatchNumber) (interf sealTime, err := z.state.GetLastL2BlockTimeByBatchNumber(ctx, batchNumber, dbTx) if err != nil { - return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get last l2 block time from state batch number %v, error: %v", batchNumber, err), nil, false) + return RPCErrorResponse(types.DefaultErrorCode, fmt.Sprintf("couldn't get batch number %v's seal time, error: %v", batchNumber, err), nil, false) } return hex.EncodeUint64(sealTime), nil