Skip to content

Commit

Permalink
Merge branch 'main' into rianhughes/rpc8-getMessageStatus2
Browse files Browse the repository at this point in the history
  • Loading branch information
rianhughes committed Nov 7, 2024
2 parents fb08240 + ef7e174 commit 60d072e
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 42 deletions.
15 changes: 10 additions & 5 deletions cmd/juno/juno.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (
dbPathF = "db-path"
networkF = "network"
ethNodeF = "eth-node"
disableL1VerificationF = "disable-l1-verification"
pprofF = "pprof"
pprofHostF = "pprof-host"
pprofPortF = "pprof-port"
Expand Down Expand Up @@ -91,6 +92,7 @@ const (
defaultWS = false
defaultWSPort = 6061
defaultEthNode = ""
defaultDisableL1Verification = false
defaultPprof = false
defaultPprofPort = 6062
defaultColour = true
Expand Down Expand Up @@ -145,11 +147,12 @@ const (
colourUsage = "Use `--colour=false` command to disable colourized outputs (ANSI Escape Codes)."
ethNodeUsage = "WebSocket endpoint of the Ethereum node. To verify the correctness of the L2 chain, " +
"Juno must connect to an Ethereum node and parse events in the Starknet contract."
pendingPollIntervalUsage = "Sets how frequently pending block will be updated (0s will disable fetching of pending block)."
p2pUsage = "EXPERIMENTAL: Enables p2p server."
p2pAddrUsage = "EXPERIMENTAL: Specify p2p listening source address as multiaddr. Example: /ip4/0.0.0.0/tcp/7777"
p2pPublicAddrUsage = "EXPERIMENTAL: Specify p2p public address as multiaddr. Example: /ip4/35.243.XXX.XXX/tcp/7777"
p2pPeersUsage = "EXPERIMENTAL: Specify list of p2p peers split by a comma. " +
disableL1VerificationUsage = "Disables L1 verification since an Ethereum node is not provided."
pendingPollIntervalUsage = "Sets how frequently pending block will be updated (0s will disable fetching of pending block)."
p2pUsage = "EXPERIMENTAL: Enables p2p server."
p2pAddrUsage = "EXPERIMENTAL: Specify p2p listening source address as multiaddr. Example: /ip4/0.0.0.0/tcp/7777"
p2pPublicAddrUsage = "EXPERIMENTAL: Specify p2p public address as multiaddr. Example: /ip4/35.243.XXX.XXX/tcp/7777"
p2pPeersUsage = "EXPERIMENTAL: Specify list of p2p peers split by a comma. " +
"These peers can be either Feeder or regular nodes."
p2pFeederNodeUsage = "EXPERIMENTAL: Run juno as a feeder node which will only sync from feeder gateway and gossip the new" +
" blocks to the network."
Expand Down Expand Up @@ -327,6 +330,8 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
junoCmd.Flags().String(cnCoreContractAddressF, defaultCNCoreContractAddressStr, networkCustomCoreContractAddressUsage)
junoCmd.Flags().IntSlice(cnUnverifiableRangeF, defaultCNUnverifiableRange, networkCustomUnverifiableRange)
junoCmd.Flags().String(ethNodeF, defaultEthNode, ethNodeUsage)
junoCmd.Flags().Bool(disableL1VerificationF, defaultDisableL1Verification, disableL1VerificationUsage)
junoCmd.MarkFlagsMutuallyExclusive(ethNodeF, disableL1VerificationF)
junoCmd.Flags().Bool(pprofF, defaultPprof, pprofUsage)
junoCmd.Flags().String(pprofHostF, defaulHost, pprofHostUsage)
junoCmd.Flags().Uint16(pprofPortF, defaultPprofPort, pprofPortUsage)
Expand Down
33 changes: 19 additions & 14 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type Config struct {
DatabasePath string `mapstructure:"db-path"`
Network utils.Network `mapstructure:"network"`
EthNode string `mapstructure:"eth-node"`
DisableL1Verification bool `mapstructure:"disable-l1-verification"`
Pprof bool `mapstructure:"pprof"`
PprofHost string `mapstructure:"pprof-host"`
PprofPort uint16 `mapstructure:"pprof-port"`
Expand Down Expand Up @@ -273,18 +274,22 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen
metricsService: metricsService,
}

if n.cfg.EthNode == "" {
n.log.Warnw("Ethereum node address not found; will not verify against L1")
n.log.Warnw("L1 client not found, cannot serve starknet_getMessage")
} else {
var l1ClientService *l1.Client
var l1EthSubscriber l1.Subscriber
l1ClientService, l1EthSubscriber, err = newL1Client(cfg, n.blockchain, n.log)
if !n.cfg.DisableL1Verification {
// Due to mutually exclusive flag we can do the following.
if n.cfg.EthNode == "" {
return nil, fmt.Errorf("ethereum node address not found; Use --disable-l1-verification flag if L1 verification is not required")
}

var l1Client *l1.Client
var l1Subscriber l1.Subscriber
l1Client, l1Subscriber, err = newL1Client(cfg.EthNode, cfg.Metrics, n.blockchain, n.log)

Check warning on line 285 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L284-L285

Added lines #L284 - L285 were not covered by tests
if err != nil {
return nil, fmt.Errorf("create L1 client: %w", err)
}
n.services = append(n.services, l1ClientService)
rpcHandler.WithETHClient(l1EthSubscriber)
n.services = append(n.services, l1Client)
rpcHandler.WithETHClient(l1Subscriber)

Check warning on line 290 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L290

Added line #L290 was not covered by tests
} else {
n.log.Warnw("L1 client not found, cannot serve starknet_getMessage RPC endpoint")
}

if semversion, err := semver.NewVersion(version); err == nil {
Expand All @@ -297,26 +302,26 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen
return n, nil
}

func newL1Client(cfg *Config, chain *blockchain.Blockchain, log utils.SimpleLogger) (*l1.Client, l1.Subscriber, error) {
ethNodeURL, err := url.Parse(cfg.EthNode)
func newL1Client(ethNode string, includeMetrics bool, chain *blockchain.Blockchain, log utils.SimpleLogger) (*l1.Client, l1.Subscriber, error) {

Check warning on line 305 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L305

Added line #L305 was not covered by tests
ethNodeURL, err := url.Parse(ethNode)
if err != nil {
return nil, nil, fmt.Errorf("parse Ethereum node URL: %w", err)

Check warning on line 308 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L308

Added line #L308 was not covered by tests
}
if ethNodeURL.Scheme != "wss" && ethNodeURL.Scheme != "ws" {
return nil, nil, errors.New("non-websocket Ethereum node URL (need wss://... or ws://...): " + cfg.EthNode)
return nil, nil, errors.New("non-websocket Ethereum node URL (need wss://... or ws://...): " + ethNode)

Check warning on line 311 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L311

Added line #L311 was not covered by tests
}

network := chain.Network()

var ethSubscriber *l1.EthSubscriber
ethSubscriber, err = l1.NewEthSubscriber(cfg.EthNode, network.CoreContractAddress)
ethSubscriber, err = l1.NewEthSubscriber(ethNode, network.CoreContractAddress)
if err != nil {
return nil, nil, fmt.Errorf("set up ethSubscriber: %w", err)

Check warning on line 319 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L319

Added line #L319 was not covered by tests
}

l1Client := l1.NewClient(ethSubscriber, chain, log)

if cfg.Metrics {
if includeMetrics {
l1Client.WithEventListener(makeL1Metrics())
}
return l1Client, ethSubscriber, nil

Check warning on line 327 in node/node.go

View check run for this annotation

Codecov / codecov/patch

node/node.go#L327

Added line #L327 was not covered by tests
Expand Down
44 changes: 23 additions & 21 deletions node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,26 @@ import (
// Create a new node with all services enabled.
func TestNewNode(t *testing.T) {
config := &node.Config{
LogLevel: utils.INFO,
HTTP: true,
HTTPPort: 0,
Websocket: true,
WebsocketPort: 0,
GRPC: true,
GRPCPort: 0,
DatabasePath: t.TempDir(),
Network: utils.Sepolia, // P2P will only work with Sepolia (for the time being)
EthNode: "",
Pprof: true,
PprofPort: 0,
Colour: true,
PendingPollInterval: time.Second,
Metrics: true,
MetricsPort: 0,
P2P: true,
P2PAddr: "",
P2PPeers: "",
LogLevel: utils.INFO,
HTTP: true,
HTTPPort: 0,
Websocket: true,
WebsocketPort: 0,
GRPC: true,
GRPCPort: 0,
DatabasePath: t.TempDir(),
Network: utils.Sepolia, // P2P will only work with Sepolia (for the time being)
EthNode: "",
DisableL1Verification: true,
Pprof: true,
PprofPort: 0,
Colour: true,
PendingPollInterval: time.Second,
Metrics: true,
MetricsPort: 0,
P2P: true,
P2PAddr: "",
P2PPeers: "",
}

n, err := node.New(config, "v0.3")
Expand Down Expand Up @@ -77,8 +78,9 @@ func TestNetworkVerificationOnNonEmptyDB(t *testing.T) {
require.NoError(t, database.Close())

_, err = node.New(&node.Config{
DatabasePath: dbPath,
Network: test.network,
DatabasePath: dbPath,
Network: test.network,
DisableL1Verification: true,
}, "v0.1")
if test.errString == "" {
require.NoError(t, err)
Expand Down
14 changes: 14 additions & 0 deletions rpc/contract.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package rpc

import (
"errors"

"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/db"
"github.com/NethermindEth/juno/jsonrpc"
)

Expand Down Expand Up @@ -39,6 +42,17 @@ func (h *Handler) StorageAt(address, key felt.Felt, id BlockID) (*felt.Felt, *js
}
defer h.callAndLogErr(stateCloser, "Error closing state reader in getStorageAt")

// This checks if the contract exists because if a key doesn't exist in contract storage,
// the returned value is always zero and error is nil.
_, err := stateReader.ContractClassHash(&address)
if err != nil {
if errors.Is(err, db.ErrKeyNotFound) {
return nil, ErrContractNotFound
}
h.log.Errorw("Failed to get contract nonce", "err", err)
return nil, ErrInternal
}

value, err := stateReader.ContractStorage(&address, &key)
if err != nil {
return nil, ErrContractNotFound
Expand Down
8 changes: 6 additions & 2 deletions rpc/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func TestStorageAt(t *testing.T) {

t.Run("non-existent contract", func(t *testing.T) {
mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(nil, errors.New("non-existent contract"))
mockState.EXPECT().ContractClassHash(gomock.Any()).Return(nil, db.ErrKeyNotFound)

storage, rpcErr := handler.StorageAt(felt.Zero, felt.Zero, rpc.BlockID{Latest: true})
require.Nil(t, storage)
Expand All @@ -132,7 +132,8 @@ func TestStorageAt(t *testing.T) {

t.Run("non-existent key", func(t *testing.T) {
mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(&felt.Zero, errors.New("non-existent key"))
mockState.EXPECT().ContractClassHash(&felt.Zero).Return(nil, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(nil, db.ErrKeyNotFound)

storage, rpcErr := handler.StorageAt(felt.Zero, felt.Zero, rpc.BlockID{Latest: true})
require.Nil(t, storage)
Expand All @@ -143,6 +144,7 @@ func TestStorageAt(t *testing.T) {

t.Run("blockID - latest", func(t *testing.T) {
mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil)
mockState.EXPECT().ContractClassHash(&felt.Zero).Return(nil, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(expectedStorage, nil)

storage, rpcErr := handler.StorageAt(felt.Zero, felt.Zero, rpc.BlockID{Latest: true})
Expand All @@ -152,6 +154,7 @@ func TestStorageAt(t *testing.T) {

t.Run("blockID - hash", func(t *testing.T) {
mockReader.EXPECT().StateAtBlockHash(&felt.Zero).Return(mockState, nopCloser, nil)
mockState.EXPECT().ContractClassHash(&felt.Zero).Return(nil, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(expectedStorage, nil)

storage, rpcErr := handler.StorageAt(felt.Zero, felt.Zero, rpc.BlockID{Hash: &felt.Zero})
Expand All @@ -161,6 +164,7 @@ func TestStorageAt(t *testing.T) {

t.Run("blockID - number", func(t *testing.T) {
mockReader.EXPECT().StateAtBlockNumber(uint64(0)).Return(mockState, nopCloser, nil)
mockState.EXPECT().ContractClassHash(&felt.Zero).Return(nil, nil)
mockState.EXPECT().ContractStorage(gomock.Any(), gomock.Any()).Return(expectedStorage, nil)

storage, rpcErr := handler.StorageAt(felt.Zero, felt.Zero, rpc.BlockID{Number: 0})
Expand Down

0 comments on commit 60d072e

Please sign in to comment.