diff --git a/cmd/service/init.go b/cmd/service/init.go index beec216..c48a422 100644 --- a/cmd/service/init.go +++ b/cmd/service/init.go @@ -8,7 +8,6 @@ import ( postgres_keystore "github.com/grassrootseconomics/cic-custodial/internal/keystore/providers/postgres" "github.com/grassrootseconomics/cic-custodial/internal/noncestore" redis_noncestore "github.com/grassrootseconomics/cic-custodial/internal/noncestore/providers/redis" - system_provider "github.com/grassrootseconomics/cic-custodial/internal/system" tasker_client "github.com/grassrootseconomics/cic-custodial/internal/tasker/client" "github.com/grassrootseconomics/cic-go-sdk/chain" "github.com/knadh/koanf" @@ -65,19 +64,6 @@ func initChainProvider() *chain.Provider { return provider } -func initSystemProvider() *system_provider.SystemProvider { - systemProvider, err := system_provider.NewSystemProvider(system_provider.Opts{ - SystemPublicKey: ko.MustString("admin.public"), - SystemPrivateKey: ko.MustString("admin.key"), - ChainProvider: chainProvider, - }) - if err != nil { - lo.Fatal("initSystemProvider", "error", err) - } - - return systemProvider -} - func initTaskerClient() *tasker_client.TaskerClient { return tasker_client.NewTaskerClient(tasker_client.Opts{ RedisDSN: ko.MustString("tasker.dsn"), diff --git a/cmd/service/main.go b/cmd/service/main.go index 85f09de..ee19d04 100644 --- a/cmd/service/main.go +++ b/cmd/service/main.go @@ -42,12 +42,17 @@ func main() { taskerClient = initTaskerClient() - actionsProvider := actions.NewActionsProvider(actions.Opts{ - SystemProvider: initSystemProvider(), - ChainProvider: chainProvider, - Keystore: initKeystore(), - Noncestore: initNoncestore(), + actionsProvider, err := actions.NewActionsProvider(actions.Opts{ + SystemPublicKey: ko.MustString("admin.public"), + SystemPrivateKey: ko.MustString("admin.key"), + ChainProvider: chainProvider, + Keystore: initKeystore(), + Noncestore: initNoncestore(), + Logger: lo, }) + if err != nil { + lo.Fatal("initActionsProvider", "err", err) + } httpServer = api.BootstrapHTTPServer(api.Opts{ ActionsProvider: actionsProvider, diff --git a/internal/actions/actions.go b/internal/actions/actions.go index bda26ae..4700e75 100644 --- a/internal/actions/actions.go +++ b/internal/actions/actions.go @@ -2,13 +2,15 @@ package actions import ( "context" + "crypto/ecdsa" "github.com/ethereum/go-ethereum/core/types" + eth_crypto "github.com/ethereum/go-ethereum/crypto" "github.com/grassrootseconomics/cic-custodial/internal/ethereum" "github.com/grassrootseconomics/cic-custodial/internal/keystore" "github.com/grassrootseconomics/cic-custodial/internal/noncestore" - system_provider "github.com/grassrootseconomics/cic-custodial/internal/system" "github.com/grassrootseconomics/cic-go-sdk/chain" + "github.com/zerodha/logf" ) type Actions interface { @@ -24,26 +26,46 @@ type Actions interface { } type Opts struct { - SystemProvider *system_provider.SystemProvider - ChainProvider *chain.Provider - Keystore keystore.Keystore - Noncestore noncestore.Noncestore + SystemPublicKey string + SystemPrivateKey string + ChainProvider *chain.Provider + Keystore keystore.Keystore + Noncestore noncestore.Noncestore + Logger logf.Logger } type ActionsProvider struct { - SystemProvider *system_provider.SystemProvider - ChainProvider *chain.Provider - Keystore keystore.Keystore - Noncestore noncestore.Noncestore + SystemPublicKey string + SystemPrivateKey *ecdsa.PrivateKey + ChainProvider *chain.Provider + Keystore keystore.Keystore + Noncestore noncestore.Noncestore + Lo logf.Logger } -func NewActionsProvider(o Opts) *ActionsProvider { +func NewActionsProvider(o Opts) (*ActionsProvider, error) { var _ Actions = (*ActionsProvider)(nil) - return &ActionsProvider{ - SystemProvider: o.SystemProvider, - ChainProvider: o.ChainProvider, - Keystore: o.Keystore, - Noncestore: o.Noncestore, + loadedPrivateKey, err := eth_crypto.HexToECDSA(o.SystemPrivateKey) + if err != nil { + return nil, err } + + _, err = o.Noncestore.Peek(context.Background(), o.SystemPublicKey) + if err != nil { + nonce, err := o.Noncestore.SyncNetworkNonce(context.Background(), o.SystemPublicKey) + o.Logger.Debug("actionsProvider: syncing system nonce", "nonce", nonce) + if err != nil { + return nil, err + } + } + + return &ActionsProvider{ + SystemPublicKey: o.SystemPublicKey, + SystemPrivateKey: loadedPrivateKey, + ChainProvider: o.ChainProvider, + Keystore: o.Keystore, + Noncestore: o.Noncestore, + Lo: o.Logger, + }, nil } diff --git a/internal/actions/system.go b/internal/actions/system.go index 5d6855d..d106a9c 100644 --- a/internal/actions/system.go +++ b/internal/actions/system.go @@ -15,9 +15,14 @@ const ( ) func (ap *ActionsProvider) SignGiftGasTx(ctx context.Context, giftTo string) (*types.Transaction, error) { - builtTx, err := ap.ChainProvider.BuildGasTransferTx(ap.SystemProvider.SystemPrivateKey, chain.TransactionData{ + nonce, err := ap.Noncestore.Acquire(ctx, ap.SystemPublicKey) + if err != nil { + return nil, err + } + + builtTx, err := ap.ChainProvider.BuildGasTransferTx(ap.SystemPrivateKey, chain.TransactionData{ To: w3.A(giftTo), - Nonce: ap.SystemProvider.SystemNoncestore.Acquire(), + Nonce: nonce, }, big.NewInt(initialGiftGasValue)) if err != nil { return &types.Transaction{}, err @@ -27,9 +32,14 @@ func (ap *ActionsProvider) SignGiftGasTx(ctx context.Context, giftTo string) (*t } func (ap *ActionsProvider) SignTopUpGasTx(ctx context.Context, giftTo string) (*types.Transaction, error) { - builtTx, err := ap.ChainProvider.BuildGasTransferTx(ap.SystemProvider.SystemPrivateKey, chain.TransactionData{ + nonce, err := ap.Noncestore.Acquire(ctx, ap.SystemPublicKey) + if err != nil { + return nil, err + } + + builtTx, err := ap.ChainProvider.BuildGasTransferTx(ap.SystemPrivateKey, chain.TransactionData{ To: w3.A(giftTo), - Nonce: ap.SystemProvider.SystemNoncestore.Acquire(), + Nonce: nonce, }, big.NewInt(topupGiftGasValue)) if err != nil { return &types.Transaction{}, err diff --git a/internal/noncestore/noncestore.go b/internal/noncestore/noncestore.go index e10de9a..ed4e22c 100644 --- a/internal/noncestore/noncestore.go +++ b/internal/noncestore/noncestore.go @@ -10,10 +10,3 @@ type Noncestore interface { SyncNetworkNonce(context.Context, string) (uint64, error) SetNewAccountNonce(context.Context, string) error } - -// SystemNoncestore represents a standalone noncestore for a single system account -type SystemNoncestore interface { - Peek() uint64 - Acquire() uint64 - Return() -} diff --git a/internal/noncestore/providers/redis/redis.go b/internal/noncestore/providers/redis/redis.go index 267a88b..3c15e28 100644 --- a/internal/noncestore/providers/redis/redis.go +++ b/internal/noncestore/providers/redis/redis.go @@ -13,7 +13,8 @@ import ( ) const ( - mutexLockTTL = 200 * time.Millisecond + mutexLockTTL = 200 * time.Millisecond + mutexKeyPrefix = "lock_" ) // Opts represents the Redis nonce store specific params @@ -52,7 +53,7 @@ func NewRedisNoncestore(o Opts) (noncestore.Noncestore, error) { } func (ns *RedisNoncestore) Peek(ctx context.Context, publicKey string) (uint64, error) { - lock, err := ns.redisLockProvider.Obtain(ctx, publicKey, mutexLockTTL, nil) + lock, err := ns.redisLockProvider.Obtain(ctx, mutexKeyPrefix+publicKey, mutexLockTTL, nil) if err != nil { return 0, err } @@ -71,7 +72,7 @@ func (ns *RedisNoncestore) Acquire(ctx context.Context, publicKey string) (uint6 nonce uint64 ) - lock, err := ns.redisLockProvider.Obtain(ctx, publicKey, mutexLockTTL, nil) + lock, err := ns.redisLockProvider.Obtain(ctx, mutexKeyPrefix+publicKey, mutexLockTTL, nil) if err != nil { return 0, err } @@ -98,7 +99,7 @@ func (ns *RedisNoncestore) Acquire(ctx context.Context, publicKey string) (uint6 } func (ns *RedisNoncestore) Return(ctx context.Context, publicKey string) (uint64, error) { - lock, err := ns.redisLockProvider.Obtain(ctx, publicKey, mutexLockTTL, nil) + lock, err := ns.redisLockProvider.Obtain(ctx, mutexKeyPrefix+publicKey, mutexLockTTL, nil) if err != nil { return 0, err } @@ -124,7 +125,7 @@ func (ns *RedisNoncestore) SyncNetworkNonce(ctx context.Context, publicKey strin networkNonce uint64 ) - lock, err := ns.redisLockProvider.Obtain(ctx, publicKey, mutexLockTTL, nil) + lock, err := ns.redisLockProvider.Obtain(ctx, mutexKeyPrefix+publicKey, mutexLockTTL, nil) if err != nil { return 0, err } @@ -147,7 +148,7 @@ func (ns *RedisNoncestore) SyncNetworkNonce(ctx context.Context, publicKey strin } func (ns *RedisNoncestore) SetNewAccountNonce(ctx context.Context, publicKey string) error { - lock, err := ns.redisLockProvider.Obtain(ctx, publicKey, mutexLockTTL, nil) + lock, err := ns.redisLockProvider.Obtain(ctx, mutexKeyPrefix+publicKey, mutexLockTTL, nil) if err != nil { return err } diff --git a/internal/noncestore/providers/system/system.go b/internal/noncestore/providers/system/system.go deleted file mode 100644 index cc7922c..0000000 --- a/internal/noncestore/providers/system/system.go +++ /dev/null @@ -1,65 +0,0 @@ -package system - -import ( - "context" - "sync" - - "github.com/grassrootseconomics/cic-custodial/internal/noncestore" - "github.com/grassrootseconomics/cic-go-sdk/chain" - "github.com/lmittmann/w3" - "github.com/lmittmann/w3/module/eth" -) - -type Opts struct { - ChainProvider *chain.Provider - AccountAddress string -} - -type SystemNoncestore struct { - mx sync.Mutex - nonceValue uint64 -} - -func NewSystemNoncestore(o Opts) (noncestore.SystemNoncestore, error) { - var ( - networkNonce uint64 - ) - - err := o.ChainProvider.EthClient.CallCtx( - context.Background(), - eth.Nonce(w3.A(o.AccountAddress), nil).Returns(&networkNonce), - ) - if err != nil { - return nil, err - } - - return &SystemNoncestore{ - nonceValue: networkNonce, - }, nil -} - -func (ns *SystemNoncestore) Peek() uint64 { - ns.mx.Lock() - defer ns.mx.Unlock() - - return ns.nonceValue -} - -func (ns *SystemNoncestore) Acquire() uint64 { - ns.mx.Lock() - defer ns.mx.Unlock() - - nextNonce := ns.nonceValue - ns.nonceValue++ - - return nextNonce -} - -func (ns *SystemNoncestore) Return() { - ns.mx.Lock() - defer ns.mx.Unlock() - - if ns.nonceValue > 0 { - ns.nonceValue-- - } -} diff --git a/internal/system/system.go b/internal/system/system.go deleted file mode 100644 index b3771d4..0000000 --- a/internal/system/system.go +++ /dev/null @@ -1,43 +0,0 @@ -package system - -import ( - "crypto/ecdsa" - - eth_crypto "github.com/ethereum/go-ethereum/crypto" - "github.com/grassrootseconomics/cic-custodial/internal/noncestore" - system_noncestore "github.com/grassrootseconomics/cic-custodial/internal/noncestore/providers/system" - "github.com/grassrootseconomics/cic-go-sdk/chain" -) - -type Opts struct { - SystemPublicKey string - SystemPrivateKey string - ChainProvider *chain.Provider -} - -type SystemProvider struct { - SystemNoncestore noncestore.SystemNoncestore - SystemPublicKey string - SystemPrivateKey *ecdsa.PrivateKey -} - -func NewSystemProvider(o Opts) (*SystemProvider, error) { - loadedPrivateKey, err := eth_crypto.HexToECDSA(o.SystemPrivateKey) - if err != nil { - return nil, err - } - - systemNoncestore, err := system_noncestore.NewSystemNoncestore(system_noncestore.Opts{ - ChainProvider: o.ChainProvider, - AccountAddress: o.SystemPublicKey, - }) - if err != nil { - return nil, err - } - - return &SystemProvider{ - SystemNoncestore: systemNoncestore, - SystemPublicKey: o.SystemPublicKey, - SystemPrivateKey: loadedPrivateKey, - }, nil -}