From c8431d8f08302c587fdaf546163b663e4bd32f10 Mon Sep 17 00:00:00 2001 From: Xinran <1576710154@qq.com> Date: Tue, 16 Apr 2024 22:47:04 +0800 Subject: [PATCH] blockWithTxHashes RPC (#36) --- README.md | 2 + cairo/api.go | 87 +++++++++++++++++++++++++++++++++--------- cairo/cairo.go | 2 +- starknetrpc/methods.go | 10 +++++ starknetrpc/rpc.go | 5 +++ 5 files changed, 87 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c5b6df4..743b204 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ The genesis configs of Itachi chain is same as Madara. You can learn more detail - [x] getClassAt - [x] getClassHashAt - [ ] blockHashAndNumber +- [ ] getBlockWithTxHashes - [ ] getBlockWithTxs - [x] chainId - [ ] syncing @@ -93,6 +94,7 @@ The genesis configs of Itachi chain is same as Madara. You can learn more detail - [x] getClassAt - [x] getClassHashAt - [ ] blockHashAndNumber +- [x] getBlockWithTxHashes - [x] getBlockWithTxs - [x] chainId - [ ] syncing diff --git a/cairo/api.go b/cairo/api.go index 5012e62..10d7e98 100644 --- a/cairo/api.go +++ b/cairo/api.go @@ -101,6 +101,45 @@ func (c *Cairo) getReceipt(hash felt.Felt) (*rpc.TransactionReceipt, error) { return starkReceipt, err } +type BlockWithTxHashesRequest struct { + BlockID BlockID `json:"block_id"` +} + +type BlockWithTxHashesResponse struct { + BlockWithTxHashes *rpc.BlockWithTxHashes `json:"block_with_tx_hashes"` + Err *jsonrpc.Error `json:"err"` +} + +func (c *Cairo) GetBlockWithTxHashes(ctx *context.ReadContext) { + var br BlockWithTxHashesRequest + err := ctx.BindJson(&br) + if err != nil { + ctx.Json(http.StatusBadRequest, &BlockWithTxsResponse{Err: jsonrpc.Err(jsonrpc.InvalidJSON, err.Error())}) + return + } + + var compactBlock *types.CompactBlock + compactBlock, err = c.getYuBlock(br.BlockID) + if err != nil { + ctx.Json(http.StatusInternalServerError, &BlockWithTxsResponse{Err: jsonrpc.Err(jsonrpc.InternalError, err.Error())}) + return + } + + status := rpc.BlockAcceptedL2 + if br.BlockID.Pending { + status = rpc.BlockPending + } + txHashes := make([]*felt.Felt, 0) + for _, txHash := range compactBlock.TxnsHashes { + txHashes = append(txHashes, new(felt.Felt).SetBytes(txHash.Bytes())) + } + ctx.JsonOk(&BlockWithTxHashesResponse{BlockWithTxHashes: &rpc.BlockWithTxHashes{ + Status: status, + BlockHeader: c.adaptStarkBlockHeader(compactBlock), + TxnHashes: txHashes, + }}) +} + type BlockWithTxsRequest struct { BlockID BlockID `json:"block_id"` } @@ -119,12 +158,7 @@ func (c *Cairo) GetBlockWithTxs(ctx *context.ReadContext) { } var compactBlock *types.CompactBlock - switch { - case br.BlockID.Latest || br.BlockID.Pending: - compactBlock, err = c.Chain.GetEndBlock() - default: - compactBlock, err = c.Chain.GetBlockByHeight(common.BlockNum(br.BlockID.Number)) - } + compactBlock, err = c.getYuBlock(br.BlockID) if err != nil { ctx.Json(http.StatusInternalServerError, &BlockWithTxsResponse{Err: jsonrpc.Err(jsonrpc.InternalError, err.Error())}) return @@ -147,25 +181,42 @@ func (c *Cairo) GetBlockWithTxs(ctx *context.ReadContext) { starkTxs = append(starkTxs, &txReq.Tx.Transaction) } - num := uint64(compactBlock.Height) + status := rpc.BlockAcceptedL2 + if br.BlockID.Pending { + status = rpc.BlockPending + } blockWithTxs := &rpc.BlockWithTxs{ - Status: rpc.BlockAcceptedL2, - BlockHeader: rpc.BlockHeader{ - Hash: new(felt.Felt).SetBytes(compactBlock.Hash.Bytes()), - ParentHash: new(felt.Felt).SetBytes(compactBlock.PrevHash.Bytes()), - Number: &num, - // FIXME - NewRoot: new(felt.Felt).SetBytes(compactBlock.StateRoot.Bytes()), - Timestamp: compactBlock.Timestamp, - SequencerAddress: c.sequencerAddr, - // TODO:L1GasPrice, StarknetVersion - }, + Status: status, + BlockHeader: c.adaptStarkBlockHeader(compactBlock), Transactions: starkTxs, } ctx.JsonOk(&BlockWithTxsResponse{BlockWithTxs: blockWithTxs}) } +func (c *Cairo) getYuBlock(id BlockID) (*types.CompactBlock, error) { + switch { + case id.Latest || id.Pending: + return c.Chain.GetEndBlock() + default: + return c.Chain.GetBlockByHeight(common.BlockNum(id.Number)) + } +} + +func (c *Cairo) adaptStarkBlockHeader(yuBlock *types.CompactBlock) rpc.BlockHeader { + num := uint64(yuBlock.Height) + return rpc.BlockHeader{ + Hash: new(felt.Felt).SetBytes(yuBlock.Hash.Bytes()), + ParentHash: new(felt.Felt).SetBytes(yuBlock.PrevHash.Bytes()), + Number: &num, + // FIXME + NewRoot: new(felt.Felt).SetBytes(yuBlock.StateRoot.Bytes()), + Timestamp: yuBlock.Timestamp, + SequencerAddress: c.sequencerAddr, + // TODO:L1GasPrice, StarknetVersion + } +} + type TransactionStatusRequest struct { Hash felt.Felt `json:"hash"` } diff --git a/cairo/cairo.go b/cairo/cairo.go index 818e0ea..8b530c1 100644 --- a/cairo/cairo.go +++ b/cairo/cairo.go @@ -58,7 +58,7 @@ func NewCairo(cfg *config.Config) *Cairo { cairo.GetClassHashAt, cairo.GetNonce, cairo.GetStorage, cairo.GetTransaction, cairo.GetTransactionStatus, cairo.GetReceipt, cairo.SimulateTransactions, - cairo.GetBlockWithTxs, + cairo.GetBlockWithTxs, cairo.GetBlockWithTxHashes, ) cairo.SetInit(cairo) cairo.SetTxnChecker(cairo) diff --git a/starknetrpc/methods.go b/starknetrpc/methods.go index f68dd29..ed22900 100644 --- a/starknetrpc/methods.go +++ b/starknetrpc/methods.go @@ -21,6 +21,16 @@ func (s *StarknetRPC) GetChainID() (*felt.Felt, *jsonrpc.Error) { return s.network.ChainID(), nil } +func (s *StarknetRPC) GetBlockWithTxHashes(id rpc.BlockID) (*rpc.BlockWithTxHashes, *jsonrpc.Error) { + req := &cairo.BlockWithTxHashesRequest{BlockID: cairo.NewFromJunoBlockID(id)} + resp, jsonErr := s.adaptChainRead(req, "GetBlockWithTxHashes") + if jsonErr != nil { + return nil, jsonErr + } + res := resp.DataInterface.(*cairo.BlockWithTxHashesResponse) + return res.BlockWithTxHashes, res.Err +} + func (s *StarknetRPC) GetBlockWithTxs(id rpc.BlockID) (*rpc.BlockWithTxs, *jsonrpc.Error) { req := &cairo.BlockWithTxsRequest{BlockID: cairo.NewFromJunoBlockID(id)} resp, jsonErr := s.adaptChainRead(req, "GetBlockWithTxs") diff --git a/starknetrpc/rpc.go b/starknetrpc/rpc.go index 1597c9f..32bb506 100644 --- a/starknetrpc/rpc.go +++ b/starknetrpc/rpc.go @@ -111,6 +111,11 @@ func (s *StarknetRPC) Methods() ([]jsonrpc.Method, string) { Name: "starknet_specVersion", Handler: s.SpecVersion, }, + { + Name: "starknet_getBlockWithTxHashes", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: s.GetBlockWithTxHashes, + }, { Name: "starknet_getBlockWithTxs", Params: []jsonrpc.Parameter{{Name: "block_id"}},