Skip to content

Commit

Permalink
feat(state): Integrate new Signer for concurrent tx submission (#3298)
Browse files Browse the repository at this point in the history
Closes: #3296

This adds the
[`Signer`](https://github.com/celestiaorg/celestia-app/blob/bcab06582c9802f1d49a2bee86820792258bb587/pkg/user/signer.go#L31)
struct from celestia-app's user package.

Signer keeps track of both the network and local sequence number
allowing for multiple messages to be signed within a single block.

This also uses the `EstimateGas` function of the signer to estimate the
gas, when the user provides 0 as the `gasLim`

TODO: we should probably introduce some gas multiplier (default: 1.1) to
the `EstimateGas` as it seems to underestimate the value (cc @vgonkivs)

---------

Co-authored-by: rene <[email protected]>
  • Loading branch information
cmwaters and renaynay authored Apr 18, 2024
1 parent 500116d commit 6382dc1
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 177 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/BurntSushi/toml v1.3.2
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
github.com/benbjohnson/clock v1.3.5
github.com/celestiaorg/celestia-app v1.7.0
github.com/celestiaorg/celestia-app v1.8.0-rc0
github.com/celestiaorg/go-fraud v0.2.0
github.com/celestiaorg/go-header v0.6.0
github.com/celestiaorg/go-libp2p-messenger v0.2.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/celestiaorg/celestia-app v1.7.0 h1:pFIgQzeMD036ulJ2ShUR/3bDGG6kwNAWaLEE0MXHmgg=
github.com/celestiaorg/celestia-app v1.7.0/go.mod h1:z2H47Gs9gYd3GdQ22d5sbcL8/aBMRcVDtUWT64goMaY=
github.com/celestiaorg/celestia-app v1.8.0-rc0 h1:rjEwN0Im1+2QChr8uPfbdomhGL3lEmGlt0cPUodc5JU=
github.com/celestiaorg/celestia-app v1.8.0-rc0/go.mod h1:z2H47Gs9gYd3GdQ22d5sbcL8/aBMRcVDtUWT64goMaY=
github.com/celestiaorg/celestia-core v1.35.0-tm-v0.34.29 h1:sXERzNXgyHyqTKNQx4S29C/NMDzgav62DaQDNF49HUQ=
github.com/celestiaorg/celestia-core v1.35.0-tm-v0.34.29/go.mod h1:weZR4wYx1Vcw3g1Jc5G8VipG4M+KUDSqeIzyyWszmsQ=
github.com/celestiaorg/cosmos-sdk v1.20.1-sdk-v0.46.16 h1:9U9UthIJSOyVjabD5PkD6aczvqlWOyAFTOXw0duPT5k=
Expand Down
6 changes: 1 addition & 5 deletions nodebuilder/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,11 @@ func ConstructModule(tp node.Type, network p2p.Network, cfg *Config, store Store
if err != nil {
return fx.Error(err)
}
signer, err := state.KeyringSigner(cfg.State, ks, network)
if err != nil {
return fx.Error(err)
}

baseComponents := fx.Options(
fx.Supply(tp),
fx.Supply(network),
fx.Supply(ks),
fx.Provide(p2p.BootstrappersFor),
fx.Provide(func(lc fx.Lifecycle) context.Context {
return fxutil.WithLifecycle(context.Background(), lc)
Expand All @@ -45,7 +42,6 @@ func ConstructModule(tp node.Type, network p2p.Network, cfg *Config, store Store
fx.Provide(store.Datastore),
fx.Provide(store.Keystore),
fx.Supply(node.StorePath(store.Path())),
fx.Supply(signer),
// modules provided by the node
p2p.ConstructModule(tp, &cfg.P2P),
state.ConstructModule(tp, &cfg.State, &cfg.Core),
Expand Down
20 changes: 15 additions & 5 deletions nodebuilder/state/core.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package state

import (
apptypes "github.com/celestiaorg/celestia-app/x/blob/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"

libfraud "github.com/celestiaorg/go-fraud"
"github.com/celestiaorg/go-header/sync"

Expand All @@ -16,16 +17,25 @@ import (
// a celestia-core connection.
func coreAccessor(
corecfg core.Config,
signer *apptypes.KeyringSigner,
keyring keyring.Keyring,
keyname AccountName,
sync *sync.Syncer[*header.ExtendedHeader],
fraudServ libfraud.Service[*header.ExtendedHeader],
opts []state.Option,
) (*state.CoreAccessor, Module, *modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]) {
ca := state.NewCoreAccessor(signer, sync, corecfg.IP, corecfg.RPCPort, corecfg.GRPCPort, opts...)
) (
*state.CoreAccessor,
Module,
*modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader],
error,
) {
ca, err := state.NewCoreAccessor(keyring, string(keyname), sync, corecfg.IP, corecfg.RPCPort, corecfg.GRPCPort,
opts...)

sBreaker := &modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]{
Service: ca,
FraudType: byzantine.BadEncoding,
FraudServ: fraudServ,
}
return ca, ca, sBreaker

return ca, ca, sBreaker, err
}
22 changes: 8 additions & 14 deletions nodebuilder/state/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,36 @@ package state
import (
kr "github.com/cosmos/cosmos-sdk/crypto/keyring"

apptypes "github.com/celestiaorg/celestia-app/x/blob/types"

"github.com/celestiaorg/celestia-node/libs/keystore"
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
)

const DefaultAccountName = "my_celes_key"

// KeyringSigner constructs a new keyring signer.
// NOTE: we construct keyring signer before constructing node for easier UX
type AccountName string

// Keyring constructs a new keyring.
// NOTE: we construct keyring before constructing node for easier UX
// as having keyring-backend set to `file` prompts user for password.
func KeyringSigner(cfg Config, ks keystore.Keystore, net p2p.Network) (*apptypes.KeyringSigner, error) {
func Keyring(cfg Config, ks keystore.Keystore) (kr.Keyring, AccountName, error) {
ring := ks.Keyring()
var info *kr.Record
// if custom keyringAccName provided, find key for that name
if cfg.KeyringAccName != "" {
keyInfo, err := ring.Key(cfg.KeyringAccName)
if err != nil {
log.Errorw("failed to find key by given name", "keyring.accname", cfg.KeyringAccName)
return nil, err
return nil, "", err
}
info = keyInfo
} else {
// use default key
keyInfo, err := ring.Key(DefaultAccountName)
if err != nil {
log.Errorw("could not access key in keyring", "name", DefaultAccountName)
return nil, err
return nil, "", err
}
info = keyInfo
}
// construct signer using the default key found / generated above
signer := apptypes.NewKeyringSigner(ring, info.Name, string(net))
signerInfo := signer.GetSignerInfo()
log.Infow("constructed keyring signer", "backend", cfg.KeyringBackend, "path", ks.Path(),
"key name", signerInfo.Name, "chain-id", string(net))

return signer, nil
return ring, AccountName(info.Name), nil
}
5 changes: 5 additions & 0 deletions nodebuilder/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package state
import (
"context"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
logging "github.com/ipfs/go-log/v2"
"go.uber.org/fx"

"github.com/celestiaorg/celestia-node/header"
"github.com/celestiaorg/celestia-node/libs/fxutil"
"github.com/celestiaorg/celestia-node/libs/keystore"
"github.com/celestiaorg/celestia-node/nodebuilder/core"
modfraud "github.com/celestiaorg/celestia-node/nodebuilder/fraud"
"github.com/celestiaorg/celestia-node/nodebuilder/node"
Expand All @@ -29,6 +31,9 @@ func ConstructModule(tp node.Type, cfg *Config, coreCfg *core.Config) fx.Option
fx.Supply(*cfg),
fx.Error(cfgErr),
fx.Supply(opts),
fx.Provide(func(ks keystore.Keystore) (keyring.Keyring, AccountName, error) {
return Keyring(*cfg, ks)
}),
fxutil.ProvideIf(coreCfg.IsEndpointConfigured(), fx.Annotate(
coreAccessor,
fx.OnStart(func(ctx context.Context,
Expand Down
14 changes: 10 additions & 4 deletions nodebuilder/state/opts.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package state

import (
kr "github.com/cosmos/cosmos-sdk/crypto/keyring"
"go.uber.org/fx"

"github.com/celestiaorg/celestia-app/x/blob/types"
"github.com/celestiaorg/celestia-node/libs/fxutil"
)

// WithKeyringSigner overrides the default keyring signer constructed
// WithKeyring overrides the default keyring constructed
// by the node.
func WithKeyringSigner(signer *types.KeyringSigner) fx.Option {
return fx.Replace(signer)
func WithKeyring(keyring kr.Keyring) fx.Option {
return fxutil.ReplaceAs(keyring, new(kr.Keyring))
}

// WithKeyName configures the signer to use the given key.
func WithKeyName(name AccountName) fx.Option {
return fx.Replace(name)
}
19 changes: 7 additions & 12 deletions nodebuilder/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/fx"

apptypes "github.com/celestiaorg/celestia-app/x/blob/types"
libhead "github.com/celestiaorg/go-header"

"github.com/celestiaorg/celestia-node/core"
Expand All @@ -17,9 +16,10 @@ import (
"github.com/celestiaorg/celestia-node/libs/fxutil"
"github.com/celestiaorg/celestia-node/nodebuilder/node"
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
"github.com/celestiaorg/celestia-node/nodebuilder/state"
)

const TestKeyringName = "test_celes"

// MockStore provides mock in memory Store for testing purposes.
func MockStore(t *testing.T, cfg *Config) Store {
t.Helper()
Expand Down Expand Up @@ -48,10 +48,13 @@ func TestNodeWithConfig(t *testing.T, tp node.Type, cfg *Config, opts ...fx.Opti
store := MockStore(t, cfg)
ks, err := store.Keystore()
require.NoError(t, err)
kr := ks.Keyring()
// create a key in the keystore to be used by the core accessor
_, _, err = kr.NewMnemonic(TestKeyringName, keyring.English, "", "", hd.Secp256k1)
require.NoError(t, err)
cfg.State.KeyringAccName = TestKeyringName

opts = append(opts,
// avoid writing keyring on disk
state.WithKeyringSigner(TestKeyringSigner(t, ks.Keyring())),
// temp dir for the eds store FIXME: Should be in mem
fx.Replace(node.StorePath(t.TempDir())),
// avoid requesting trustedPeer during initialization
Expand All @@ -71,11 +74,3 @@ func TestNodeWithConfig(t *testing.T, tp node.Type, cfg *Config, opts ...fx.Opti
require.NoError(t, err)
return nd
}

func TestKeyringSigner(t *testing.T, ring keyring.Keyring) *apptypes.KeyringSigner {
signer := apptypes.NewKeyringSigner(ring, "", string(p2p.Private))
_, _, err := signer.NewMnemonic("my_celes_key", keyring.English, "",
"", hd.Secp256k1)
require.NoError(t, err)
return signer
}
2 changes: 0 additions & 2 deletions nodebuilder/tests/blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ func TestBlobModule(t *testing.T) {
blobs = append(blobs, blob)
}

require.NoError(t, err)
bridge := sw.NewBridgeNode()
require.NoError(t, bridge.Start(ctx))

addrs, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(bridge.Host))
require.NoError(t, err)

Expand Down
5 changes: 2 additions & 3 deletions nodebuilder/tests/swamp/swamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"golang.org/x/exp/maps"

"github.com/celestiaorg/celestia-app/test/util/testnode"
apptypes "github.com/celestiaorg/celestia-app/x/blob/types"
libhead "github.com/celestiaorg/go-header"

"github.com/celestiaorg/celestia-node/core"
Expand Down Expand Up @@ -258,9 +257,9 @@ func (s *Swamp) NewNodeWithStore(
store nodebuilder.Store,
options ...fx.Option,
) *nodebuilder.Node {
signer := apptypes.NewKeyringSigner(s.ClientContext.Keyring, s.Accounts[0], s.ClientContext.ChainID)
options = append(options,
state.WithKeyringSigner(signer),
state.WithKeyring(s.ClientContext.Keyring),
state.WithKeyName(state.AccountName(s.Accounts[0])),
)

switch tp {
Expand Down
Loading

0 comments on commit 6382dc1

Please sign in to comment.