From 9dbf82a488f2940963b60567744f2ed5d65b38c0 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 11 Oct 2023 19:48:54 -0400 Subject: [PATCH] Remove write lock option from the avm rpc API (#2156) --- vms/avm/service.go | 77 ++++++++++++++++++++++-- vms/avm/service_test.go | 130 ++++++++++++++++++++++++++++++++++++++++ vms/avm/vm.go | 2 +- 3 files changed, 204 insertions(+), 5 deletions(-) diff --git a/vms/avm/service.go b/vms/avm/service.go index 6d1948ffda57..f0ce5aef5daa 100644 --- a/vms/avm/service.go +++ b/vms/avm/service.go @@ -72,6 +72,9 @@ func (s *Service) GetBlock(_ *http.Request, args *api.GetBlockArgs, reply *api.G zap.Stringer("encoding", args.Encoding), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + if s.vm.chainManager == nil { return errNotLinearized } @@ -115,6 +118,9 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr zap.Uint64("height", uint64(args.Height)), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + if s.vm.chainManager == nil { return errNotLinearized } @@ -166,6 +172,9 @@ func (s *Service) GetHeight(_ *http.Request, _ *struct{}, reply *api.GetHeightRe zap.String("method", "getHeight"), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + if s.vm.chainManager == nil { return errNotLinearized } @@ -196,6 +205,10 @@ func (s *Service) IssueTx(_ *http.Request, args *api.FormattedTx, reply *api.JSO if err != nil { return fmt.Errorf("problem decoding transaction: %w", err) } + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + txID, err := s.vm.IssueTx(txBytes) if err != nil { return err @@ -263,6 +276,9 @@ func (s *Service) GetAddressTxs(_ *http.Request, args *GetAddressTxsArgs, reply zap.Uint64("pageSize", pageSize), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Read transactions from the indexer reply.TxIDs, err = s.vm.addressTxsIndexer.Read(address[:], assetID, cursor, pageSize) if err != nil { @@ -296,6 +312,9 @@ func (s *Service) GetTxStatus(_ *http.Request, args *api.JSONTxID, reply *GetTxS return errNilTxID } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + _, err := s.vm.state.GetTx(args.TxID) switch err { case nil: @@ -320,6 +339,9 @@ func (s *Service) GetTx(_ *http.Request, args *api.GetTxArgs, reply *api.GetTxRe return errNilTxID } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + tx, err := s.vm.state.GetTx(args.TxID) if err != nil { return err @@ -399,6 +421,10 @@ func (s *Service) GetUTXOs(_ *http.Request, args *api.GetUTXOsArgs, reply *api.G if limit <= 0 || int(maxPageSize) < limit { limit = int(maxPageSize) } + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + if sourceChain == s.vm.ctx.ChainID { utxos, endAddr, endUTXOID, err = avax.GetPaginatedUTXOs( s.vm.state, @@ -471,6 +497,9 @@ func (s *Service) GetAssetDescription(_ *http.Request, args *GetAssetDescription return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + tx, err := s.vm.state.GetTx(assetID) if err != nil { return err @@ -524,8 +553,10 @@ func (s *Service) GetBalance(_ *http.Request, args *GetBalanceArgs, reply *GetBa return err } - addrSet := set.Set[ids.ShortID]{} - addrSet.Add(addr) + addrSet := set.Of(addr) + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() utxos, err := avax.GetAllUTXOs(s.vm.state, addrSet) if err != nil { @@ -592,8 +623,10 @@ func (s *Service) GetAllBalances(_ *http.Request, args *GetAllBalancesArgs, repl if err != nil { return fmt.Errorf("problem parsing address '%s': %w", args.Address, err) } - addrSet := set.Set[ids.ShortID]{} - addrSet.Add(address) + addrSet := set.Of(address) + + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() utxos, err := avax.GetAllUTXOs(s.vm.state, addrSet) if err != nil { @@ -687,6 +720,9 @@ func (s *Service) CreateAsset(_ *http.Request, args *CreateAssetArgs, reply *Ass return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -842,6 +878,9 @@ func (s *Service) CreateNFTAsset(_ *http.Request, args *CreateNFTAssetArgs, repl return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -938,6 +977,9 @@ func (s *Service) CreateAddress(_ *http.Request, args *api.UserPass, reply *api. logging.UserString("username", args.Username), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password) if err != nil { return err @@ -967,6 +1009,9 @@ func (s *Service) ListAddresses(_ *http.Request, args *api.UserPass, response *a logging.UserString("username", args.Username), ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password) if err != nil { return err @@ -1019,6 +1064,9 @@ func (s *Service) ExportKey(_ *http.Request, args *ExportKeyArgs, reply *ExportK return fmt.Errorf("problem parsing address %q: %w", args.Address, err) } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password) if err != nil { return err @@ -1058,6 +1106,9 @@ func (s *Service) ImportKey(_ *http.Request, args *ImportKeyArgs, reply *api.JSO return errMissingPrivateKey } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password) if err != nil { return err @@ -1144,6 +1195,9 @@ func (s *Service) SendMultiple(_ *http.Request, args *SendMultipleArgs, reply *a return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Load user's UTXOs/keys utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -1302,6 +1356,9 @@ func (s *Service) Mint(_ *http.Request, args *MintArgs, reply *api.JSONTxIDChang return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses feeUTXOs, feeKc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -1419,6 +1476,9 @@ func (s *Service) SendNFT(_ *http.Request, args *SendNFTArgs, reply *api.JSONTxI return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -1535,6 +1595,9 @@ func (s *Service) MintNFT(_ *http.Request, args *MintNFTArgs, reply *api.JSONTxI return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses feeUTXOs, feeKc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { @@ -1651,6 +1714,9 @@ func (s *Service) Import(_ *http.Request, args *ImportArgs, reply *api.JSONTxID) return fmt.Errorf("problem parsing to address %q: %w", args.To, err) } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, nil) if err != nil { return err @@ -1793,6 +1859,9 @@ func (s *Service) Export(_ *http.Request, args *ExportArgs, reply *api.JSONTxIDC return err } + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + // Get the UTXOs/keys for the from addresses utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs) if err != nil { diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go index a0bd93f01861..15ebeba2c954 100644 --- a/vms/avm/service_test.go +++ b/vms/avm/service_test.go @@ -50,7 +50,10 @@ func TestServiceIssueTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -73,7 +76,10 @@ func TestServiceGetTxStatus(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -93,8 +99,12 @@ func TestServiceGetTxStatus(t *testing.T) { require.NoError(env.service.GetTxStatus(nil, statusArgs, statusReply)) require.Equal(choices.Unknown, statusReply.Status) + env.vm.ctx.Lock.Lock() + issueAndAccept(require, env.vm, env.issuer, newTx) + env.vm.ctx.Lock.Unlock() + statusReply = &GetTxStatusReply{} require.NoError(env.service.GetTxStatus(nil, statusArgs, statusReply)) require.Equal(choices.Accepted, statusReply.Status) @@ -106,6 +116,7 @@ func TestServiceGetBalanceStrict(t *testing.T) { env := setup(t, &envConfig{}) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -135,6 +146,8 @@ func TestServiceGetBalanceStrict(t *testing.T) { env.vm.state.AddUTXO(twoOfTwoUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs := &GetBalanceArgs{ Address: addrStr, @@ -158,6 +171,8 @@ func TestServiceGetBalanceStrict(t *testing.T) { require.Zero(balanceReply.Balance) require.Empty(balanceReply.UTXOIDs) + env.vm.ctx.Lock.Lock() + // A UTXO with a 1 out of 2 multisig // where one of the addresses is [addr] oneOfTwoUTXO := &avax.UTXO{ @@ -178,6 +193,8 @@ func TestServiceGetBalanceStrict(t *testing.T) { env.vm.state.AddUTXO(oneOfTwoUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs = &GetBalanceArgs{ Address: addrStr, @@ -201,6 +218,8 @@ func TestServiceGetBalanceStrict(t *testing.T) { require.Zero(balanceReply.Balance) require.Empty(balanceReply.UTXOIDs) + env.vm.ctx.Lock.Lock() + // A UTXO with a 1 out of 1 multisig // but with a locktime in the future now := env.vm.clock.Time() @@ -223,6 +242,8 @@ func TestServiceGetBalanceStrict(t *testing.T) { env.vm.state.AddUTXO(futureUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs = &GetBalanceArgs{ Address: addrStr, @@ -254,6 +275,7 @@ func TestServiceGetTxs(t *testing.T) { env.vm.addressTxsIndexer, err = index.NewIndexer(env.vm.db, env.vm.ctx.Log, "", prometheus.NewRegistry(), false) require.NoError(err) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -266,6 +288,8 @@ func TestServiceGetTxs(t *testing.T) { testTxCount := 25 testTxs := initTestTxIndex(t, env.vm.db, addr, assetID, testTxCount) + env.vm.ctx.Lock.Unlock() + // get the first page getTxsArgs := &GetAddressTxsArgs{ PageSize: 10, @@ -290,6 +314,7 @@ func TestServiceGetAllBalances(t *testing.T) { env := setup(t, &envConfig{}) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -318,6 +343,8 @@ func TestServiceGetAllBalances(t *testing.T) { env.vm.state.AddUTXO(twoOfTwoUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs := &GetAllBalancesArgs{ JSONAddress: api.JSONAddress{Address: addrStr}, @@ -338,6 +365,8 @@ func TestServiceGetAllBalances(t *testing.T) { require.NoError(env.service.GetAllBalances(nil, balanceArgs, reply)) require.Empty(reply.Balances) + env.vm.ctx.Lock.Lock() + // A UTXO with a 1 out of 2 multisig // where one of the addresses is [addr] oneOfTwoUTXO := &avax.UTXO{ @@ -358,6 +387,8 @@ func TestServiceGetAllBalances(t *testing.T) { env.vm.state.AddUTXO(oneOfTwoUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs = &GetAllBalancesArgs{ JSONAddress: api.JSONAddress{Address: addrStr}, @@ -379,6 +410,8 @@ func TestServiceGetAllBalances(t *testing.T) { // The balance should not include the UTXO since it is only partly owned by [addr] require.Empty(reply.Balances) + env.vm.ctx.Lock.Lock() + // A UTXO with a 1 out of 1 multisig // but with a locktime in the future now := env.vm.clock.Time() @@ -401,6 +434,8 @@ func TestServiceGetAllBalances(t *testing.T) { env.vm.state.AddUTXO(futureUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs = &GetAllBalancesArgs{ JSONAddress: api.JSONAddress{Address: addrStr}, @@ -422,6 +457,8 @@ func TestServiceGetAllBalances(t *testing.T) { // The balance should not include the UTXO since it is only partly owned by [addr] require.Empty(reply.Balances) + env.vm.ctx.Lock.Lock() + // A UTXO for a different asset otherAssetID := ids.GenerateTestID() otherAssetUTXO := &avax.UTXO{ @@ -442,6 +479,8 @@ func TestServiceGetAllBalances(t *testing.T) { env.vm.state.AddUTXO(otherAssetUTXO) require.NoError(env.vm.state.Commit()) + env.vm.ctx.Lock.Unlock() + // Check the balance with IncludePartial set to true balanceArgs = &GetAllBalancesArgs{ JSONAddress: api.JSONAddress{Address: addrStr}, @@ -472,7 +511,10 @@ func TestServiceGetTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -498,6 +540,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { env := setup(t, &envConfig{}) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -505,6 +548,8 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) { newTx := newAvaxBaseTxWithOutputs(t, env.genesisBytes, env.vm) issueAndAccept(require, env.vm, env.issuer, newTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: newTx.ID(), @@ -523,6 +568,7 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { env := setup(t, &envConfig{}) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -530,6 +576,8 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) { newTx := newAvaxExportTxWithOutputs(t, env.genesisBytes, env.vm) issueAndAccept(require, env.vm, env.issuer, newTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: newTx.ID(), @@ -553,6 +601,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -560,6 +609,8 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) { createAssetTx := newAvaxCreateAssetTxWithOutputs(t, env.vm) issueAndAccept(require, env.vm, env.issuer, createAssetTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: createAssetTx.ID(), @@ -585,6 +636,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -597,6 +649,8 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) { require.NoError(mintNFTTx.SignNFTFx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}})) issueAndAccept(require, env.vm, env.issuer, mintNFTTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintNFTTx.ID(), @@ -626,6 +680,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -641,6 +696,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) { require.NoError(mintNFTTx.SignNFTFx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}, {key}})) issueAndAccept(require, env.vm, env.issuer, mintNFTTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintNFTTx.ID(), @@ -669,6 +726,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -681,6 +739,8 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) { require.NoError(mintSecpOpTx.SignSECP256K1Fx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}})) issueAndAccept(require, env.vm, env.issuer, mintSecpOpTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintSecpOpTx.ID(), @@ -712,6 +772,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -727,6 +788,8 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) { require.NoError(mintSecpOpTx.SignSECP256K1Fx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}, {key}})) issueAndAccept(require, env.vm, env.issuer, mintSecpOpTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintSecpOpTx.ID(), @@ -756,6 +819,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -768,6 +832,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) { require.NoError(mintPropertyFxOpTx.SignPropertyFx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}})) issueAndAccept(require, env.vm, env.issuer, mintPropertyFxOpTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintPropertyFxOpTx.ID(), @@ -798,6 +864,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) }}, }) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -813,6 +880,8 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T) require.NoError(mintPropertyFxOpTx.SignPropertyFx(env.vm.parser.Codec(), [][]*secp256k1.PrivateKey{{key}, {key}})) issueAndAccept(require, env.vm, env.issuer, mintPropertyFxOpTx) + env.vm.ctx.Lock.Unlock() + reply := api.GetTxReply{} require.NoError(env.service.GetTx(nil, &api.GetTxArgs{ TxID: mintPropertyFxOpTx.ID(), @@ -1074,7 +1143,10 @@ func TestServiceGetNilTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1088,7 +1160,10 @@ func TestServiceGetUnknownTx(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1101,6 +1176,7 @@ func TestServiceGetUnknownTx(t *testing.T) { func TestServiceGetUTXOs(t *testing.T) { env := setup(t, &envConfig{}) defer func() { + env.vm.ctx.Lock.Lock() require.NoError(t, env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1175,6 +1251,8 @@ func TestServiceGetUTXOs(t *testing.T) { xEmptyAddr, err := env.vm.FormatLocalAddress(rawEmptyAddr) require.NoError(t, err) + env.vm.ctx.Lock.Unlock() + tests := []struct { label string count int @@ -1352,7 +1430,10 @@ func TestGetAssetDescription(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1372,7 +1453,10 @@ func TestGetBalance(t *testing.T) { require := require.New(t) env := setup(t, &envConfig{}) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1403,7 +1487,10 @@ func TestCreateFixedCapAsset(t *testing.T) { initialKeys: keys, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1451,7 +1538,10 @@ func TestCreateVariableCapAsset(t *testing.T) { initialKeys: keys, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1484,8 +1574,12 @@ func TestCreateVariableCapAsset(t *testing.T) { }, &reply)) require.Equal(changeAddrStr, reply.ChangeAddr) + env.vm.ctx.Lock.Lock() + buildAndAccept(require, env.vm, env.issuer, reply.AssetID) + env.vm.ctx.Lock.Unlock() + createdAssetID := reply.AssetID.String() // Test minting of the created variable cap asset mintArgs := &MintArgs{ @@ -1504,8 +1598,12 @@ func TestCreateVariableCapAsset(t *testing.T) { require.NoError(env.service.Mint(nil, mintArgs, mintReply)) require.Equal(changeAddrStr, mintReply.ChangeAddr) + env.vm.ctx.Lock.Lock() + buildAndAccept(require, env.vm, env.issuer, mintReply.TxID) + env.vm.ctx.Lock.Unlock() + sendArgs := &SendArgs{ JSONSpendHeader: api.JSONSpendHeader{ UserPass: api.UserPass{ @@ -1541,7 +1639,10 @@ func TestNFTWorkflow(t *testing.T) { initialKeys: keys, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1576,8 +1677,12 @@ func TestNFTWorkflow(t *testing.T) { require.NoError(env.service.CreateNFTAsset(nil, createArgs, createReply)) require.Equal(fromAddrsStr[0], createReply.ChangeAddr) + env.vm.ctx.Lock.Lock() + buildAndAccept(require, env.vm, env.issuer, createReply.AssetID) + env.vm.ctx.Lock.Unlock() + // Key: Address // Value: AVAX balance balances := map[ids.ShortID]uint64{} @@ -1627,9 +1732,13 @@ func TestNFTWorkflow(t *testing.T) { require.NoError(env.service.MintNFT(nil, mintArgs, mintReply)) require.Equal(fromAddrsStr[0], createReply.ChangeAddr) + env.vm.ctx.Lock.Lock() + // Accept the transaction so that we can send the newly minted NFT buildAndAccept(require, env.vm, env.issuer, mintReply.TxID) + env.vm.ctx.Lock.Unlock() + sendArgs := &SendNFTArgs{ JSONSpendHeader: api.JSONSpendHeader{ UserPass: api.UserPass{ @@ -1659,7 +1768,10 @@ func TestImportExportKey(t *testing.T) { password: password, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1701,7 +1813,10 @@ func TestImportAVMKeyNoDuplicates(t *testing.T) { password: password, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1750,6 +1865,8 @@ func TestSend(t *testing.T) { initialKeys: keys, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -1783,6 +1900,8 @@ func TestSend(t *testing.T) { require.NoError(env.service.Send(nil, args, reply)) require.Equal(changeAddrStr, reply.ChangeAddr) + env.vm.ctx.Lock.Lock() + buildAndAccept(require, env.vm, env.issuer, reply.TxID) } @@ -1799,6 +1918,8 @@ func TestSendMultiple(t *testing.T) { initialKeys: keys, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() @@ -1839,6 +1960,8 @@ func TestSendMultiple(t *testing.T) { require.NoError(env.service.SendMultiple(nil, args, reply)) require.Equal(changeAddrStr, reply.ChangeAddr) + env.vm.ctx.Lock.Lock() + buildAndAccept(require, env.vm, env.issuer, reply.TxID) }) } @@ -1853,7 +1976,10 @@ func TestCreateAndListAddresses(t *testing.T) { password: password, }}, }) + env.vm.ctx.Lock.Unlock() + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1891,7 +2017,9 @@ func TestImport(t *testing.T) { initialKeys: keys, }}, }) + defer func() { + env.vm.ctx.Lock.Lock() require.NoError(env.vm.Shutdown(context.Background())) env.vm.ctx.Lock.Unlock() }() @@ -1926,6 +2054,8 @@ func TestImport(t *testing.T) { }, })) + env.vm.ctx.Lock.Unlock() + addrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address()) require.NoError(err) args := &ImportArgs{ diff --git a/vms/avm/vm.go b/vms/avm/vm.go index 23bffb2105e3..3a89a24d338f 100644 --- a/vms/avm/vm.go +++ b/vms/avm/vm.go @@ -341,7 +341,7 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]*common.HTTPHandler, e err := walletServer.RegisterService(&vm.walletService, "wallet") return map[string]*common.HTTPHandler{ - "": {Handler: rpcServer}, + "": {LockOptions: common.NoLock, Handler: rpcServer}, "/wallet": {LockOptions: common.NoLock, Handler: walletServer}, "/events": {LockOptions: common.NoLock, Handler: vm.pubsub}, }, err