From 704d4d1c004d0df47e22abc6d1c4664898675546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 12 Jan 2024 13:13:48 +0900 Subject: [PATCH] txm: Test now runs but signing is invalid --- ops/charts/devnet/templates/deployment.yaml | 2 +- ops/scripts/devnet-hardhat-down.sh | 16 +++--- ops/scripts/devnet-hardhat.sh | 5 +- .../chainlink/ocr2/contract_transmitter.go | 6 +- relayer/pkg/chainlink/txm/nonce.go | 10 ++-- relayer/pkg/chainlink/txm/nonce_test.go | 2 +- relayer/pkg/chainlink/txm/test_helpers.go | 1 - relayer/pkg/chainlink/txm/txm.go | 28 +++++----- relayer/pkg/chainlink/txm/txm_test.go | 56 ++++++++++++------- relayer/pkg/starknet/client.go | 8 +-- 10 files changed, 76 insertions(+), 58 deletions(-) diff --git a/ops/charts/devnet/templates/deployment.yaml b/ops/charts/devnet/templates/deployment.yaml index 50e22e7a3..df4bc41e7 100644 --- a/ops/charts/devnet/templates/deployment.yaml +++ b/ops/charts/devnet/templates/deployment.yaml @@ -48,7 +48,7 @@ spec: - name: cairo-build mountPath: /cairo-build image: "{{ .Values.repository | default "shardlabs/starknet-devnet-rs"}}:{{ .Values.tag | default "latest"}}" - args: ["--port", {{ .Values.service.internalPort | quote}}, "--seed", {{ .Values.seed | quote}}] + args: ["--port", {{ .Values.service.internalPort | quote}}, "--seed", {{ .Values.seed | quote}}, "--account-class", "cairo1"] {{- end }} imagePullPolicy: IfNotPresent {{- if eq .Values.real_node true }} diff --git a/ops/scripts/devnet-hardhat-down.sh b/ops/scripts/devnet-hardhat-down.sh index 193628820..4b9b02111 100755 --- a/ops/scripts/devnet-hardhat-down.sh +++ b/ops/scripts/devnet-hardhat-down.sh @@ -1,25 +1,25 @@ #!/usr/bin/env bash # TODO: this script needs to be replaced with a predefined K8s enviroment -echo "Cleaning up Starknet Devnet container..." +echo "Cleaning up Hardhat container..." -dpid=`docker ps | grep chainlink-starknet.starknet-devnet | awk '{print $1}'`; -echo "Checking for existing 'chainlink-starknet.starknet-devnet' docker container..." +dpid=`docker ps | grep chainlink-starknet.hardhat | awk '{print $1}'`; +echo "Checking for existing 'chainlink-starknet.hardhat' docker container..." if [ -z "$dpid" ] then - echo "No docker Starknet Devnet container running."; + echo "No docker Hardhat container running."; else docker kill $dpid; docker rm $dpid; fi -echo "Cleaning up Hardhat container..." +echo "Cleaning up Starknet Devnet container..." -dpid=`docker ps | grep chainlink-starknet.hardhat | awk '{print $1}'`; -echo "Checking for existing 'chainlink-starknet.hardhat' docker container..." +dpid=`docker ps | grep chainlink-starknet.starknet-devnet | awk '{print $1}'`; +echo "Checking for existing 'chainlink-starknet.starknet-devnet' docker container..." if [ -z "$dpid" ] then - echo "No docker Hardhat container running."; + echo "No docker Starknet Devnet container running."; else docker kill $dpid; docker rm $dpid; diff --git a/ops/scripts/devnet-hardhat.sh b/ops/scripts/devnet-hardhat.sh index 24163644a..e4b202d8f 100755 --- a/ops/scripts/devnet-hardhat.sh +++ b/ops/scripts/devnet-hardhat.sh @@ -27,8 +27,11 @@ docker run \ -p 127.0.0.1:5050:5050 \ -p 127.0.0.1:8545:8545 \ -d \ + -e RUST_LOG=debug \ --name chainlink-starknet.starknet-devnet \ - "shardlabs/starknet-devnet-rs:${container_version}" + "shardlabs/starknet-devnet-rs:${container_version}" \ + --seed 0 \ + --account-class cairo1 echo "Starting hardhat..." docker run --net container:chainlink-starknet.starknet-devnet -d --name chainlink-starknet.hardhat ethereumoptimism/hardhat-node:nightly diff --git a/relayer/pkg/chainlink/ocr2/contract_transmitter.go b/relayer/pkg/chainlink/ocr2/contract_transmitter.go index 32b7c98a9..d05da007b 100644 --- a/relayer/pkg/chainlink/ocr2/contract_transmitter.go +++ b/relayer/pkg/chainlink/ocr2/contract_transmitter.go @@ -7,9 +7,9 @@ import ( "github.com/pkg/errors" + "github.com/NethermindEth/juno/core/felt" starknetrpc "github.com/NethermindEth/starknet.go/rpc" starknetutils "github.com/NethermindEth/starknet.go/utils" - "github.com/NethermindEth/juno/core/felt" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/ocr2/medianreport" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm" @@ -23,7 +23,7 @@ type contractTransmitter struct { reader *transmissionsCache contractAddress *felt.Felt - senderAddress *felt.Felt + senderAddress *felt.Felt // account.publicKey accountAddress *felt.Felt txm txm.TxManager @@ -96,7 +96,7 @@ func (c *contractTransmitter) Transmit( return err } - err = c.txm.Enqueue(c.senderAddress, c.accountAddress, starknetrpc.FunctionCall{ + err = c.txm.Enqueue(c.accountAddress, c.senderAddress, starknetrpc.FunctionCall{ ContractAddress: c.contractAddress, EntryPointSelector: starknetutils.GetSelectorFromNameFelt("transmit"), Calldata: calldata, diff --git a/relayer/pkg/chainlink/txm/nonce.go b/relayer/pkg/chainlink/txm/nonce.go index 7d9587548..85436b3ae 100644 --- a/relayer/pkg/chainlink/txm/nonce.go +++ b/relayer/pkg/chainlink/txm/nonce.go @@ -21,7 +21,7 @@ type NonceManagerClient interface { type NonceManager interface { services.Service - Register(ctx context.Context, address *felt.Felt, chainId string, client NonceManagerClient) error + Register(ctx context.Context, address *felt.Felt, publicKey *felt.Felt, chainId string, client NonceManagerClient) error NextSequence(address *felt.Felt, chainID string) (*felt.Felt, error) IncrementNextSequence(address *felt.Felt, chainID string, currentNonce *felt.Felt) error @@ -65,12 +65,12 @@ func (nm *nonceManager) HealthReport() map[string]error { } // Register is used because we cannot pre-fetch nonces. the pubkey is known before hand, but the account address is not known until a job is started and sends a tx -func (nm *nonceManager) Register(ctx context.Context, addr *felt.Felt, chainId string, client NonceManagerClient) error { +func (nm *nonceManager) Register(ctx context.Context, addr *felt.Felt, publicKey *felt.Felt, chainId string, client NonceManagerClient) error { nm.lock.Lock() defer nm.lock.Unlock() - addressNonces, exists := nm.n[addr.String()] + addressNonces, exists := nm.n[publicKey.String()] if !exists { - nm.n[addr.String()] = map[string]*felt.Felt{} + nm.n[publicKey.String()] = map[string]*felt.Felt{} } _, exists = addressNonces[chainId] if !exists { @@ -78,7 +78,7 @@ func (nm *nonceManager) Register(ctx context.Context, addr *felt.Felt, chainId s if err != nil { return err } - nm.n[addr.String()][chainId] = n + nm.n[publicKey.String()][chainId] = n } return nil diff --git a/relayer/pkg/chainlink/txm/nonce_test.go b/relayer/pkg/chainlink/txm/nonce_test.go index 37600adf4..3ccfab00e 100644 --- a/relayer/pkg/chainlink/txm/nonce_test.go +++ b/relayer/pkg/chainlink/txm/nonce_test.go @@ -31,7 +31,7 @@ func newTestNonceManager(t *testing.T, chainID string, initNonce *felt.Felt) (tx c.On("AccountNonce", mock.Anything, mock.Anything).Return(initNonce, nil).Once() require.NoError(t, nm.Start(tests.Context(t))) - require.NoError(t, nm.Register(tests.Context(t), keyHash, chainID, c)) + require.NoError(t, nm.Register(tests.Context(t), keyHash, keyHash, chainID, c)) return nm, keyHash, func() { require.NoError(t, nm.Close()) } } diff --git a/relayer/pkg/chainlink/txm/test_helpers.go b/relayer/pkg/chainlink/txm/test_helpers.go index 9b5e10e7e..8cadf9307 100644 --- a/relayer/pkg/chainlink/txm/test_helpers.go +++ b/relayer/pkg/chainlink/txm/test_helpers.go @@ -37,7 +37,6 @@ func SetupLocalStarknetNode(t *testing.T) string { cmd := exec.Command("starknet-devnet", "--seed", "0", // use same seed for testing "--port", port, - "--lite-mode", ) var stdErr bytes.Buffer cmd.Stderr = &stdErr diff --git a/relayer/pkg/chainlink/txm/txm.go b/relayer/pkg/chainlink/txm/txm.go index 152d5d9d2..a3036c5f7 100644 --- a/relayer/pkg/chainlink/txm/txm.go +++ b/relayer/pkg/chainlink/txm/txm.go @@ -27,12 +27,12 @@ const ( ) type TxManager interface { - Enqueue(senderAddress *felt.Felt, accountAddress *felt.Felt, txFn starknetrpc.FunctionCall) error + Enqueue(accountAddress *felt.Felt, publicKey *felt.Felt, txFn starknetrpc.FunctionCall) error InflightCount() (int, int) } type Tx struct { - senderAddress *felt.Felt + publicKey *felt.Felt accountAddress *felt.Felt call starknetrpc.FunctionCall } @@ -114,7 +114,7 @@ func (txm *starktxm) broadcastLoop() { tx := <-txm.queue // broadcast tx serially - wait until accepted by mempool before processing next - hash, err := txm.broadcast(ctx, tx.senderAddress, tx.accountAddress, tx.call) + hash, err := txm.broadcast(ctx, tx.publicKey, tx.accountAddress, tx.call) if err != nil { txm.lggr.Errorw("transaction failed to broadcast", "error", err, "tx", tx.call) } else { @@ -126,15 +126,15 @@ func (txm *starktxm) broadcastLoop() { const FEE_MARGIN uint64 = 115 -func (txm *starktxm) broadcast(ctx context.Context, senderAddress *felt.Felt, accountAddress *felt.Felt, call starknetrpc.FunctionCall) (txhash string, err error) { +func (txm *starktxm) broadcast(ctx context.Context, publicKey *felt.Felt, accountAddress *felt.Felt, call starknetrpc.FunctionCall) (txhash string, err error) { client, err := txm.client.Get() if err != nil { txm.client.Reset() return txhash, fmt.Errorf("broadcast: failed to fetch client: %+w", err) } // create new account - accountVersion := 0 - account, err := starknetaccount.NewAccount(client.Provider, senderAddress, accountAddress.String(), txm.ks, accountVersion) + cairoVersion := 2 + account, err := starknetaccount.NewAccount(client.Provider, accountAddress, publicKey.String(), txm.ks, cairoVersion) if err != nil { return txhash, fmt.Errorf("failed to create new account: %+w", err) } @@ -144,7 +144,7 @@ func (txm *starktxm) broadcast(ctx context.Context, senderAddress *felt.Felt, ac return txhash, fmt.Errorf("failed to get chainID: %+w", err) } - nonce, err := txm.nonce.NextSequence(accountAddress, chainID) + nonce, err := txm.nonce.NextSequence(publicKey, chainID) if err != nil { return txhash, fmt.Errorf("failed to get nonce: %+w", err) } @@ -174,7 +174,7 @@ func (txm *starktxm) broadcast(ctx context.Context, senderAddress *felt.Felt, ac // Signing of the transaction that is done by the account err = account.SignInvokeTransaction(context.Background(), &tx) if err != nil { - return txhash, err + return txhash, fmt.Errorf("failed to sign tx: %+w", err) } // get fee for tx @@ -292,13 +292,13 @@ func (txm *starktxm) HealthReport() map[string]error { return map[string]error{txm.Name(): txm.Healthy()} } -func (txm *starktxm) Enqueue(senderAddress, accountAddress *felt.Felt, tx starknetrpc.FunctionCall) error { +func (txm *starktxm) Enqueue(accountAddress, publicKey *felt.Felt, tx starknetrpc.FunctionCall) error { // validate key exists for sender // use the embedded Loopp Keystore to do this; the spec and design // encourage passing nil data to the loop.Keystore.Sign as way to test // existence of a key - if _, err := txm.ks.Loopp().Sign(context.Background(), senderAddress.String(), nil); err != nil { - return err + if _, err := txm.ks.Loopp().Sign(context.Background(), publicKey.String(), nil); err != nil { + return fmt.Errorf("enqueue: failed to sign: %+w", err) } client, err := txm.client.Get() @@ -313,12 +313,12 @@ func (txm *starktxm) Enqueue(senderAddress, accountAddress *felt.Felt, tx starkn } // register account for nonce manager - if err := txm.nonce.Register(context.TODO(), accountAddress, chainID, client); err != nil { - return err + if err := txm.nonce.Register(context.TODO(), accountAddress, publicKey, chainID, client); err != nil { + return fmt.Errorf("failed to register nonce: %+w", err) } select { - case txm.queue <- Tx{senderAddress: senderAddress, accountAddress: accountAddress, call: tx}: + case txm.queue <- Tx{publicKey: publicKey, accountAddress: accountAddress, call: tx}: // TODO fix naming here default: return fmt.Errorf("failed to enqueue transaction: %+v", tx) } diff --git a/relayer/pkg/chainlink/txm/txm_test.go b/relayer/pkg/chainlink/txm/txm_test.go index b365193fd..809ab9396 100644 --- a/relayer/pkg/chainlink/txm/txm_test.go +++ b/relayer/pkg/chainlink/txm/txm_test.go @@ -26,32 +26,49 @@ import ( func TestIntegration_Txm(t *testing.T) { n := 2 // number of txs per key - url := SetupLocalStarknetNode(t) + // url := SetupLocalStarknetNode(t) + url := "http://127.0.0.1:5050" devnet := devnet.NewDevNet(url) accounts, err := devnet.Accounts() require.NoError(t, err) + fmt.Println("qqq") // parse keys into expected format - localKeys := map[string]*big.Int{} - localAccounts := map[string]string{} + type Key struct { + PrivateKey *big.Int + Account string + } + localKeys := map[string]Key{} for i := range accounts { - privKey, err := utils.HexToBytes(accounts[i].PrivateKey) - require.NoError(t, err) - senderAddress, err := starknetutils.HexToFelt(accounts[i].PublicKey) - require.NoError(t, err) - localKeys[senderAddress.String()] = utils.BytesToBig(privKey) - localAccounts[senderAddress.String()] = accounts[i].Address + publicKey := accounts[i].PublicKey + fmt.Printf("account %v pubkey %v\n", accounts[i].Address, publicKey) + localKeys[publicKey] = Key{ + PrivateKey: starknetutils.HexToBN(accounts[i].PrivateKey), + Account: accounts[i].Address, + } } + // TODO: try using official keystore & signing instead + // Initializing the account memkeyStore + // ks := account.NewMemKeystore() + // fakePrivKeyBI, ok := new(big.Int).SetString(privateKey, 0) + // if !ok { + // panic(err.Error()) + // } + // ks.Put(public_key, fakePrivKeyBI) + + // error computing loopp signature key does not exist + // mock keystore - looppKs := NewLooppKeystore(func(id string) (*big.Int, error) { - key, ok := localKeys[id] + looppKs := NewLooppKeystore(func(publicKey string) (*big.Int, error) { + key, ok := localKeys[publicKey] if !ok { - return nil, fmt.Errorf("key does not exist id=%s", id) + return nil, fmt.Errorf("key does not exist id=%s", publicKey) } - return key, nil + return key.PrivateKey, nil }) ksAdapter := NewKeystoreAdapter(looppKs) + lggr, observer := logger.TestObserved(t, zapcore.DebugLevel) timeout := 10 * time.Second client, err := starknet.NewClient("SN_GOERLI", url+"/rpc", lggr, &timeout) @@ -75,28 +92,29 @@ func TestIntegration_Txm(t *testing.T) { // start txm + checks require.NoError(t, txm.Start(context.Background())) require.NoError(t, txm.Ready()) + fmt.Println("sss") - for senderAddressStr := range localKeys { - senderAddress, err := starknetutils.HexToFelt(senderAddressStr) + for publicKeyStr := range localKeys { + publicKey, err := starknetutils.HexToFelt(publicKeyStr) require.NoError(t, err) - account, err := starknetutils.HexToFelt(localAccounts[senderAddressStr]) + accountAddress, err := starknetutils.HexToFelt(localKeys[publicKeyStr].Account) require.NoError(t, err) contractAddress, err := starknetutils.HexToFelt("0x49D36570D4E46F48E99674BD3FCC84644DDD6B96F7C741B1562B82F9E004DC7") require.NoError(t, err) - selector := utils.GetSelectorFromNameFelt("totalSupply") + selector := starknetutils.GetSelectorFromNameFelt("totalSupply") for i := 0; i < n; i++ { - require.NoError(t, txm.Enqueue(senderAddress, account, starknetrpc.FunctionCall{ + require.NoError(t, txm.Enqueue(accountAddress, publicKey, starknetrpc.FunctionCall{ ContractAddress: contractAddress, // send to ETH token contract EntryPointSelector: selector, })) } } var empty bool - for i := 0; i < 60; i++ { + for i := 0; i < 30; i++ { time.Sleep(500 * time.Millisecond) queued, unconfirmed := txm.InflightCount() accepted := len(observer.FilterMessageSnippet("ACCEPTED_ON_L2").All()) diff --git a/relayer/pkg/starknet/client.go b/relayer/pkg/starknet/client.go index e27896a4e..02de45433 100644 --- a/relayer/pkg/starknet/client.go +++ b/relayer/pkg/starknet/client.go @@ -2,7 +2,6 @@ package starknet import ( "context" - "math/big" "time" "github.com/pkg/errors" @@ -10,7 +9,6 @@ import ( "github.com/NethermindEth/juno/core/felt" starknetaccount "github.com/NethermindEth/starknet.go/account" starknetrpc "github.com/NethermindEth/starknet.go/rpc" - starknetutils "github.com/NethermindEth/starknet.go/utils" ethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -199,9 +197,9 @@ func (c *Client) AccountNonce(ctx context.Context, accountAddress *felt.Felt) (* defer cancel() } - sender := starknetutils.BigIntToFelt(big.NewInt((0))) // not actually used in account.Nonce() - accountVersion := 0 - account, err := starknetaccount.NewAccount(c.Provider, sender, accountAddress.String(), nil, accountVersion) + sender := &felt.Zero // not actually used in account.Nonce() + cairoVersion := 2 + account, err := starknetaccount.NewAccount(c.Provider, accountAddress, sender.String(), nil, cairoVersion) if err != nil { return nil, errors.Wrap(err, "error in client.AccountNonce") }