Skip to content

Commit

Permalink
implement starknet_getBlockWithReceipts
Browse files Browse the repository at this point in the history
  • Loading branch information
rianhughes committed Feb 7, 2024
1 parent dccc412 commit b762cae
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 8 deletions.
4 changes: 4 additions & 0 deletions account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,10 @@ func (account *Account) BlockWithTxs(ctx context.Context, blockID rpc.BlockID) (
return account.provider.BlockWithTxs(ctx, blockID)
}

func (account *Account) BlockWithReceipts(ctx context.Context, blockID rpc.BlockID) (interface{}, error) {
return account.provider.BlockWithReceipts(ctx, blockID)
}

// Call is a function that performs a function call on an Account.
//
// Parameters:
Expand Down
15 changes: 15 additions & 0 deletions mocks/mock_rpc_provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 44 additions & 5 deletions rpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package rpc

import (
"context"
"encoding/json"
"errors"
"fmt"

"github.com/NethermindEth/juno/core/felt"
)
Expand Down Expand Up @@ -34,8 +36,8 @@ func (provider *Provider) BlockNumber(ctx context.Context) (uint64, error) {
// - error: An error if any
func (provider *Provider) BlockHashAndNumber(ctx context.Context) (*BlockHashAndNumberOutput, error) {
var block BlockHashAndNumberOutput
if err := do(ctx, provider.c, "starknet_blockHashAndNumber", &block); err != nil {
return nil, tryUnwrapToRPCErr(err, ErrNoBlocks )
if err := do(ctx, provider.c, "starknet_blockHashAndNumber", &block); err != nil {
return nil, tryUnwrapToRPCErr(err, ErrNoBlocks)
}
return &block, nil
}
Expand All @@ -44,6 +46,7 @@ func (provider *Provider) BlockHashAndNumber(ctx context.Context) (*BlockHashAnd
//
// Parameters:
// - n: The block number to use for the BlockID.
//
// Returns:
// - BlockID: A BlockID struct with the specified block number
func WithBlockNumber(n uint64) BlockID {
Expand Down Expand Up @@ -115,8 +118,8 @@ func (provider *Provider) BlockWithTxHashes(ctx context.Context, blockID BlockID
// - error: An error, if any
func (provider *Provider) StateUpdate(ctx context.Context, blockID BlockID) (*StateUpdateOutput, error) {
var state StateUpdateOutput
if err := do(ctx, provider.c, "starknet_getStateUpdate", &state, blockID); err != nil {
return nil,tryUnwrapToRPCErr(err,ErrBlockNotFound )
if err := do(ctx, provider.c, "starknet_getStateUpdate", &state, blockID); err != nil {
return nil, tryUnwrapToRPCErr(err, ErrBlockNotFound)
}
return &state, nil
}
Expand Down Expand Up @@ -151,7 +154,7 @@ func (provider *Provider) BlockTransactionCount(ctx context.Context, blockID Blo
func (provider *Provider) BlockWithTxs(ctx context.Context, blockID BlockID) (interface{}, error) {
var result Block
if err := do(ctx, provider.c, "starknet_getBlockWithTxs", &result, blockID); err != nil {
return nil, tryUnwrapToRPCErr(err,ErrBlockNotFound )
return nil, tryUnwrapToRPCErr(err, ErrBlockNotFound)
}
// if header.Hash == nil it's a pending block
if result.BlockHeader.BlockHash == nil {
Expand All @@ -165,3 +168,39 @@ func (provider *Provider) BlockWithTxs(ctx context.Context, blockID BlockID) (in
}
return &result, nil
}

// Get block information with full transactions and receipts given the block id
func (provider *Provider) BlockWithReceipts(ctx context.Context, blockID BlockID) (interface{}, error) {
var result BlockWithReceipts
if err := do(ctx, provider.c, "starknet_getBlockWithReceipts", &result, blockID); err != nil {
return nil, tryUnwrapToRPCErr(err, ErrBlockNotFound)
}

resultBytes, err := json.Marshal(result)
if err != nil {
return nil, err
}
fmt.Println(result)

resultMap, ok := result.(map[string]interface{})
if !ok {
return nil, errors.New("result is not a map[string]interface{}")
}

// if result.Status == nil it's a pending block
if resultMap["BlockStatus"] == nil {
var pendingBlock PendingBlockWithReceipts
err := json.Unmarshal(resultBytes, &pendingBlock)
if err != nil {
return nil, err
}
return &pendingBlock, nil
}

var block BlockWithReceipts
err = json.Unmarshal(resultBytes, &block)
if err != nil {
return nil, err
}
return &block, nil
}
67 changes: 67 additions & 0 deletions rpc/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func (r *rpcMock) CallContext(ctx context.Context, result interface{}, method st
return mock_starknet_getBlockTransactionCount(result, method, args...)
case "starknet_getBlockWithTxHashes":
return mock_starknet_getBlockWithTxHashes(result, method, args...)
case "starknet_getBlockWithReceipts":
return mock_starknet_getBlockWithReceipts(result, method, args...)
case "starknet_getClass":
return mock_starknet_getClass(result, method, args...)
case "starknet_getClassAt":
Expand Down Expand Up @@ -964,6 +966,71 @@ func mock_starknet_getBlockWithTxHashes(result interface{}, method string, args
return nil
}

func mock_starknet_getBlockWithReceipts(result interface{}, method string, args ...interface{}) error {
r, ok := result.(*json.RawMessage)
if !ok || r == nil {
return errWrongType
}
if len(args) != 1 {
return errWrongArgs
}
blockId, ok := args[0].(BlockID)
if !ok {
fmt.Printf("args[0] should be BlockID, got %T\n", args[0])
return errWrongArgs
}

if blockId.Tag == "pending" {
fmt.Println("MOCK IN PENDING")
pBlock, err := json.Marshal(
PendingBlockWithReceipts{
PendingBlockHeader{
ParentHash: &felt.Zero,
Timestamp: 123,
SequencerAddress: &felt.Zero,
},
BlockBodyWithReceipts{},
},
)
if err != nil {
return err
}

return json.Unmarshal(pBlock, &r)
} else {
fmt.Println("MOCK IN REAL")
block, err := json.Marshal(
BlockWithReceipts{
BlockStatus: BlockStatus_AcceptedOnL1,
BlockHeader: BlockHeader{
BlockHash: new(felt.Felt).SetUint64(1),
ParentHash: new(felt.Felt).SetUint64(0),
Timestamp: 124,
SequencerAddress: new(felt.Felt).SetUint64(42)},
BlockBodyWithReceipts: BlockBodyWithReceipts{
Transactions: []TransactionWithReceipt{
{
Transaction: InvokeTxnV0{
Type: TransactionType_Invoke,
},
Receipt: InvokeTransactionReceipt{
TransactionHash: new(felt.Felt).SetUint64(1),
},
},
},
},
},
)
if err != nil {
return err
}

return json.Unmarshal(block, &r)
}

return nil
}

// mock_starknet_traceBlockTransactions is a function that traces the transactions of a block in the StarkNet network.
// The function first checks the type of the result parameter and returns an error if it is not of type *json.RawMessage.
// It then checks the length of the args parameter and returns an error if it is not equal to 1. Next, it checks the
Expand Down
1 change: 1 addition & 0 deletions rpc/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type RpcProvider interface {
BlockTransactionCount(ctx context.Context, blockID BlockID) (uint64, error)
BlockWithTxHashes(ctx context.Context, blockID BlockID) (interface{}, error)
BlockWithTxs(ctx context.Context, blockID BlockID) (interface{}, error)
BlockWithReceipts(ctx context.Context, blockID BlockID) (interface{}, error)
Call(ctx context.Context, call FunctionCall, block BlockID) ([]*felt.Felt, error)
ChainID(ctx context.Context) (string, error)
Class(ctx context.Context, blockID BlockID, classHash *felt.Felt) (ClassOutput, error)
Expand Down
21 changes: 21 additions & 0 deletions rpc/types_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ type PendingBlock struct {
BlockTransactions
}

type BlockWithReceipts struct {
BlockStatus `json:"status"`
BlockHeader
BlockBodyWithReceipts
}

type BlockBodyWithReceipts struct {
Transactions []TransactionWithReceipt `json:"transactions"`
}

type TransactionWithReceipt struct {
Transaction Transaction `json:"transaction,omitempty"`
Receipt TransactionReceipt `json:"receipt"`
}

// The dynamic block being constructed by the sequencer. Note that this object will be deprecated upon decentralization.
type PendingBlockWithReceipts struct {
PendingBlockHeader
BlockBodyWithReceipts
}

type BlockTxHashes struct {
BlockHeader
Status BlockStatus `json:"status"`
Expand Down
32 changes: 29 additions & 3 deletions rpc/types_block_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package rpc

import (
"context"
_ "embed"
"encoding/json"
"errors"
"testing"

"github.com/NethermindEth/juno/core/felt"
"github.com/test-go/testify/require"
)

// TestBlockID_Marshal tests the MarshalJSON method of the BlockID struct.
Expand All @@ -22,7 +24,8 @@ import (
// Parameters:
// - t: the testing object for running the test cases
// Returns:
// none
//
// none
func TestBlockID_Marshal(t *testing.T) {
blockNumber := uint64(420)
for _, tc := range []struct {
Expand Down Expand Up @@ -78,7 +81,8 @@ func TestBlockID_Marshal(t *testing.T) {
// Parameters:
// - t: A testing.T object used for reporting test failures and logging.
// Returns:
// none
//
// none
func TestBlockStatus(t *testing.T) {
for _, tc := range []struct {
status string
Expand Down Expand Up @@ -115,10 +119,32 @@ var rawBlock []byte
// Parameters:
// - t: the testing object for running the test
// Returns:
// none
//
// none
func TestBlock_Unmarshal(t *testing.T) {
b := Block{}
if err := json.Unmarshal(rawBlock, &b); err != nil {
t.Fatalf("Unmarshalling block: %v", err)
}
}

func TestBlockWithReceipts(t *testing.T) {
testConfig := beforeEach(t)

ctx := context.Background()

t.Run("BlockWithReceipts - block", func(t *testing.T) {
blockID := BlockID{Tag: "greatest block"}
block, err := testConfig.provider.BlockWithReceipts(ctx, blockID)
require.Nil(t, err)
require.NotNil(t, block)
})

t.Run("BlockWithReceipts - pending", func(t *testing.T) {
blockID := BlockID{Tag: "pending"}
block, err := testConfig.provider.BlockWithReceipts(ctx, blockID)
require.Nil(t, err)
require.NotNil(t, block)
})

}

0 comments on commit b762cae

Please sign in to comment.