diff --git a/Makefile b/Makefile index 71536c9bf..eee3d135e 100644 --- a/Makefile +++ b/Makefile @@ -263,31 +263,38 @@ endif test-e2e: build-docker-e2e test-e2e-cache - test-e2e-cache: - go test -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e - -test-e2e-cache-bcd-consumer-integration: + $(MAKE) test-e2e-cache-btc-timestamping + $(MAKE) test-e2e-cache-btc-staking +# $(MAKE) test-e2e-cache-btc-staking-integration + $(MAKE) clean-e2e + $(MAKE) test-e2e-cache-btc-staking-pre-approval + $(MAKE) test-e2e-cache-ibc-transfer + $(MAKE) test-e2e-cache-bcd-consumer-integration +# $(MAKE) test-e2e-cache-upgrade-v1 + +clean-e2e: + docker container rm -f $(shell docker container ls -a -q) || true + docker network prune -f || true + +test-e2e-cache-bcd-consumer-integration: start-bcd-consumer-integration go test -run TestBCDConsumerIntegrationTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e -test-e2e-cache-ibc-transfer: - go test -run TestIBCTranferTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e - test-e2e-cache-btc-timestamping: go test -run TestBTCTimestampingTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e -test-e2e-cache-btc-timestamping-phase-2-hermes: - go test -run TestBTCTimestampingPhase2HermesTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e - -test-e2e-cache-btc-timestamping-phase-2-rly: - go test -run TestBTCTimestampingPhase2RlyTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e - test-e2e-cache-btc-staking: go test -run TestBTCStakingTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e +test-e2e-cache-btc-staking-integration: + go test -run TestBTCStakingIntegrationTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e + test-e2e-cache-btc-staking-pre-approval: go test -run TestBTCStakingPreApprovalTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e +test-e2e-cache-ibc-transfer: + go test -run TestIBCTranferTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e + test-e2e-cache-upgrade-v1: go test -run TestSoftwareUpgradeV1TestnetTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e @@ -444,8 +451,11 @@ build-docker-e2e: build-cosmos-relayer-docker: ## Build Docker image for the Cosmos relayer $(MAKE) -C contrib/images cosmos-relayer +start-bcd-consumer-integration: + $(MAKE) -C contrib/images start-bcd-consumer-integration + clean-docker-network: - $(DOCKER) network rm ${dockerNetworkList} + $(DOCKER) network rm ${dockerNetworkList} || true build-test-wasm: ## Build WASM bindings for testing $(DOCKER) run --rm -v "$(WASM_DIR)":/code \ diff --git a/contrib/images/ibcsim-bcd/Dockerfile b/contrib/images/ibcsim-bcd/Dockerfile index e28a07b99..03a233754 100644 --- a/contrib/images/ibcsim-bcd/Dockerfile +++ b/contrib/images/ibcsim-bcd/Dockerfile @@ -16,11 +16,9 @@ ENV PATH /usr/local/go/bin:$PATH ENV GOPATH /go ENV PATH $GOPATH/bin:$PATH -WORKDIR /work - ENV GO111MODULE on ENV RELAYER_TAG v2.5.2 -ENV BABYLON_SDK_TAG v0.3.0-rc.0 +ENV BABYLON_SDK_TAG v0.6.0-rc.0 # Install the relayer RUN git clone https://github.com/cosmos/relayer.git @@ -55,8 +53,9 @@ COPY --from=build-env /go/bin/bcd /usr/bin/bcd WORKDIR /ibcsim-bcd COPY contrib/images/ibcsim-bcd/wrapper.sh /ibcsim-bcd/wrapper.sh COPY contrib/images/ibcsim-bcd/setup-bcd.sh /ibcsim-bcd/setup-bcd.sh -COPY test/e2e/bytecode/babylon_contract.wasm /ibcsim-bcd/babylon_contract.wasm -COPY test/e2e/bytecode/btc_staking.wasm /ibcsim-bcd/btc_staking.wasm +COPY --from=build-env /work/babylon-sdk/tests/testdata/babylon_contract.wasm /ibcsim-bcd/babylon_contract.wasm +COPY --from=build-env /work/babylon-sdk/tests/testdata/btc_staking.wasm /ibcsim-bcd/btc_staking.wasm +COPY --from=build-env /work/babylon-sdk/tests/testdata/btc_finality.wasm /ibcsim-bcd/btc_finality.wasm ENV BABYLON_HOME=/data/node1/babylond ENV BABYLON_NODE_RPC="http://babylondnode1:26657" diff --git a/contrib/images/ibcsim-bcd/setup-bcd.sh b/contrib/images/ibcsim-bcd/setup-bcd.sh index e8d167f8a..4780181ad 100755 --- a/contrib/images/ibcsim-bcd/setup-bcd.sh +++ b/contrib/images/ibcsim-bcd/setup-bcd.sh @@ -2,7 +2,7 @@ display_usage() { echo "Missing parameters. Please check if all parameters were specified." - echo "Usage: setup-bcd.sh [CHAIN_ID] [CHAIN_DIR] [RPC_PORT] [P2P_PORT] [PROFILING_PORT] [GRPC_PORT] [BABYLON_CONTRACT_CODE_DIR] [BTCSTAKING_CONTRACT_CODE_DIR] [INSTANTIATING_CFG]" + echo "Usage: setup-bcd.sh [CHAIN_ID] [CHAIN_DIR] [RPC_PORT] [P2P_PORT] [PROFILING_PORT] [GRPC_PORT] [BABYLON_CONTRACT_CODE_FILE] [BTCSTAKING_CONTRACT_CODE_FILE] [BTCFINALITY_CONTRACT_CODE_FILE] [INSTANTIATING_CFG]" echo "Example: setup-bcd.sh test-chain-id ./data 26657 26656 6060 9090 ./babylon_contract.wasm '{"btc_confirmation_depth":1,"checkpoint_finalization_timeout":2,"network":"Regtest","babylon_tag":"bbn0", "notify_cosmos_zone":false, "btc_staking_code_id":2}'" exit 1 } @@ -21,7 +21,7 @@ redirect() { fi } -if [ "$#" -lt "8" ]; then +if [ "$#" -lt "9" ]; then display_usage exit 1 fi @@ -32,9 +32,10 @@ RPCPORT=$3 P2PPORT=$4 PROFPORT=$5 GRPCPORT=$6 -BABYLON_CONTRACT_CODE_DIR=$7 -BTCSTAKING_CONTRACT_CODE_DIR=$8 -INSTANTIATING_CFG=$9 +BABYLON_CONTRACT_CODE_FILE=$7 +BTCSTAKING_CONTRACT_CODE_FILE=$8 +BTCFINALITY_CONTRACT_CODE_FILE=$9 +INSTANTIATING_CFG=${10} # ensure the binary exists if ! command -v $BINARY &>/dev/null; then @@ -97,8 +98,10 @@ sed -i 's/"bond_denom": "stake"/"bond_denom": "'"$DENOM"'"/g' $CHAINDIR/$CHAINID # update contract address in genesis babylonContractAddr=bbnc14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9syx25zf btcStakingContractAddr=bbnc1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqgn0kq0 +btcFinalityContractAddr=bbnc17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgssg3nft sed -i 's/"babylon_contract_address": ""/"babylon_contract_address": "'"$babylonContractAddr"'"/g' $CHAINDIR/$CHAINID/config/genesis.json sed -i 's/"btc_staking_contract_address": ""/"btc_staking_contract_address": "'"$btcStakingContractAddr"'"/g' $CHAINDIR/$CHAINID/config/genesis.json +sed -i 's/"btc_finality_contract_address": ""/"btc_finality_contract_address": "'"$btcFinalityContractAddr"'"/g' $CHAINDIR/$CHAINID/config/genesis.json # Start echo "Starting $BINARY..." @@ -106,22 +109,20 @@ $BINARY --home $CHAINDIR/$CHAINID start --pruning=nothing --grpc-web.enable=fals sleep 20 # upload contract code -echo "Uploading babylon contract code $BABYLON_CONTRACT_CODE_DIR..." -$BINARY --home $CHAINDIR/$CHAINID tx wasm store "$BABYLON_CONTRACT_CODE_DIR" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.01ustake --node http://localhost:$RPCPORT -y -sleep 5 +echo "Uploading babylon contract code $BABYLON_CONTRACT_CODE_FILE..." +$BINARY --home $CHAINDIR/$CHAINID tx wasm store "$BABYLON_CONTRACT_CODE_FILE" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.01ustake --node http://localhost:$RPCPORT -y +sleep 10 # upload contract code -echo "Uploading btcstaking contract code $BTCSTAKING_CONTRACT_CODE_DIR..." -$BINARY --home $CHAINDIR/$CHAINID tx wasm store "$BTCSTAKING_CONTRACT_CODE_DIR" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.01ustake --node http://localhost:$RPCPORT -y -sleep 5 +echo "Uploading btcstaking contract code $BTCSTAKING_CONTRACT_CODE_FILE..." +$BINARY --home $CHAINDIR/$CHAINID tx wasm store "$BTCSTAKING_CONTRACT_CODE_FILE" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.01ustake --node http://localhost:$RPCPORT -y +sleep 10 -# Echo the command with expanded variables -echo "Echoing the command with expanded variables:" -echo "Instantiating contract with code $BABYLON_CONTRACT_CODE_DIR..." -echo "$BINARY --home $CHAINDIR/$CHAINID tx wasm instantiate 1 \"$INSTANTIATING_CFG\" --admin=$(bcd --home $CHAINDIR/$CHAINID keys show user --keyring-backend test -a) --label \"v0.0.1\" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.001ustake --node http://localhost:$RPCPORT -y --amount 100000stake" +# upload contract code +echo "Uploading btcfinality contract code $BTCFINALITY_CONTRACT_CODE_FILE..." +$BINARY --home $CHAINDIR/$CHAINID tx wasm store "$BTCFINALITY_CONTRACT_CODE_FILE" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.01ustake --node http://localhost:$RPCPORT -y +sleep 10 -# Then, execute the actual command -echo "Executing the command:" -echo "Instantiating contract with code $BABYLON_CONTRACT_CODE_DIR..." +# Echo the command with expanded variables +echo "Instantiating contract $BABYLON_CONTRACT_CODE_FILE..." $BINARY --home $CHAINDIR/$CHAINID tx wasm instantiate 1 "$INSTANTIATING_CFG" --admin=$(bcd --home $CHAINDIR/$CHAINID keys show user --keyring-backend test -a) --label "v0.0.1" $KEYRING --from user --chain-id $CHAINID --gas 20000000000 --gas-prices 0.001ustake --node http://localhost:$RPCPORT -y --amount 100000stake - diff --git a/contrib/images/ibcsim-bcd/wrapper.sh b/contrib/images/ibcsim-bcd/wrapper.sh index 20947f005..2ebd63639 100755 --- a/contrib/images/ibcsim-bcd/wrapper.sh +++ b/contrib/images/ibcsim-bcd/wrapper.sh @@ -7,12 +7,7 @@ CONSUMER_KEY="bcd-key" CONSUMER_CHAIN_ID="bcd-test" # 1. Create a bcd testnet with Babylon contract -# CONSUMER_NAME="Test Consumer" -# CONSUMER_DESCRIPTION="Test Consumer Description" -# BABYLON_TAG="01020304" -# BTC_STAKING_CODE_ID=2 - -./setup-bcd.sh $CONSUMER_CHAIN_ID $CONSUMER_CONF 26657 26656 6060 9090 ./babylon_contract.wasm ./btc_staking.wasm '{ +./setup-bcd.sh $CONSUMER_CHAIN_ID $CONSUMER_CONF 26657 26656 6060 9090 ./babylon_contract.wasm ./btc_staking.wasm ./btc_finality.wasm '{ "network": "regtest", "babylon_tag": "01020304", "btc_confirmation_depth": 1, @@ -20,7 +15,8 @@ CONSUMER_CHAIN_ID="bcd-test" "notify_cosmos_zone": false, "btc_staking_code_id": 2, "consumer_name": "Test Consumer", - "consumer_description": "Test Consumer Description" + "consumer_description": "Test Consumer Description", + "btc_finality_code_id": 3 }' sleep 10 diff --git a/test/e2e/bcd_consumer_integration/clientcontroller/config/cosmwasm.go b/test/e2e/bcd_consumer_integration/clientcontroller/config/cosmwasm.go index 1cbdc1942..9c5909a01 100644 --- a/test/e2e/bcd_consumer_integration/clientcontroller/config/cosmwasm.go +++ b/test/e2e/bcd_consumer_integration/clientcontroller/config/cosmwasm.go @@ -11,26 +11,31 @@ import ( ) type CosmwasmConfig struct { - Key string `long:"key" description:"name of the key to sign transactions with"` - ChainID string `long:"chain-id" description:"chain id of the chain to connect to"` - RPCAddr string `long:"rpc-address" description:"address of the rpc server to connect to"` - GRPCAddr string `long:"grpc-address" description:"address of the grpc server to connect to"` - AccountPrefix string `long:"acc-prefix" description:"account prefix to use for addresses"` - KeyringBackend string `long:"keyring-type" description:"type of keyring to use"` - GasAdjustment float64 `long:"gas-adjustment" description:"adjustment factor when using gas estimation"` - GasPrices string `long:"gas-prices" description:"comma separated minimum gas prices to accept for transactions"` - KeyDirectory string `long:"key-dir" description:"directory to store keys in"` - Debug bool `long:"debug" description:"flag to print debug output"` - Timeout time.Duration `long:"timeout" description:"client timeout when doing queries"` - BlockTimeout time.Duration `long:"block-timeout" description:"block timeout when waiting for block events"` - OutputFormat string `long:"output-format" description:"default output when printint responses"` - SignModeStr string `long:"sign-mode" description:"sign mode to use"` - BtcStakingContractAddress string `long:"btc-staking-contract-address" description:"address of the BTC staking contract"` + Key string `long:"key" description:"name of the key to sign transactions with"` + ChainID string `long:"chain-id" description:"chain id of the chain to connect to"` + RPCAddr string `long:"rpc-address" description:"address of the rpc server to connect to"` + GRPCAddr string `long:"grpc-address" description:"address of the grpc server to connect to"` + AccountPrefix string `long:"acc-prefix" description:"account prefix to use for addresses"` + KeyringBackend string `long:"keyring-type" description:"type of keyring to use"` + GasAdjustment float64 `long:"gas-adjustment" description:"adjustment factor when using gas estimation"` + GasPrices string `long:"gas-prices" description:"comma separated minimum gas prices to accept for transactions"` + KeyDirectory string `long:"key-dir" description:"directory to store keys in"` + Debug bool `long:"debug" description:"flag to print debug output"` + Timeout time.Duration `long:"timeout" description:"client timeout when doing queries"` + BlockTimeout time.Duration `long:"block-timeout" description:"block timeout when waiting for block events"` + OutputFormat string `long:"output-format" description:"default output when printint responses"` + SignModeStr string `long:"sign-mode" description:"sign mode to use"` + BtcStakingContractAddress string `long:"btc-staking-contract-address" description:"address of the BTC staking contract"` + BtcFinalityContractAddress string `long:"btc-finality-contract-address" description:"address of the BTC finality contract"` } func (cfg *CosmwasmConfig) Validate() error { if _, err := url.Parse(cfg.RPCAddr); err != nil { - return fmt.Errorf("rpc-addr is not correctly formatted: %w", err) + return fmt.Errorf("rpc-address is not correctly formatted: %w", err) + } + + if _, err := url.Parse(cfg.GRPCAddr); err != nil { + return fmt.Errorf("grpc-address is not correctly formatted: %w", err) } if cfg.Timeout <= 0 { @@ -43,30 +48,39 @@ func (cfg *CosmwasmConfig) Validate() error { _, _, err := bech32.Decode(cfg.BtcStakingContractAddress, len(cfg.BtcStakingContractAddress)) if err != nil { - return fmt.Errorf("babylon-contract-address: invalid bech32 address: %w", err) + return fmt.Errorf("btc-staking-contract-address: invalid bech32 address: %w", err) } if !strings.HasPrefix(cfg.BtcStakingContractAddress, cfg.AccountPrefix) { - return fmt.Errorf("babylon-contract-address: invalid address prefix: %w", err) + return fmt.Errorf("btc-staking-contract-address: invalid address prefix: %w", err) + } + + _, _, err = bech32.Decode(cfg.BtcFinalityContractAddress, len(cfg.BtcFinalityContractAddress)) + if err != nil { + return fmt.Errorf("btc-finality-contract-address: invalid bech32 address: %w", err) + } + if !strings.HasPrefix(cfg.BtcFinalityContractAddress, cfg.AccountPrefix) { + return fmt.Errorf("btc-finality-contract-address: invalid address prefix: %w", err) } return nil } func DefaultCosmwasmConfig() *CosmwasmConfig { return &CosmwasmConfig{ - Key: "validator", - ChainID: "wasmd-test", - RPCAddr: "http://localhost:26677", - GRPCAddr: "https://localhost:9092", - AccountPrefix: "wasm", - KeyringBackend: "test", - GasAdjustment: 1.3, - GasPrices: "1ustake", - Debug: true, - Timeout: 20 * time.Second, - BlockTimeout: 1 * time.Minute, - OutputFormat: "direct", - SignModeStr: "", - BtcStakingContractAddress: "", + Key: "validator", + ChainID: "wasmd-test", + RPCAddr: "http://localhost:26677", + GRPCAddr: "http://localhost:9092", + AccountPrefix: "wasm", + KeyringBackend: "test", + GasAdjustment: 1.3, + GasPrices: "1ustake", + Debug: true, + Timeout: 20 * time.Second, + BlockTimeout: 1 * time.Minute, + OutputFormat: "direct", + SignModeStr: "", + BtcStakingContractAddress: "", + BtcFinalityContractAddress: "", } } @@ -75,6 +89,7 @@ func (cfg *CosmwasmConfig) ToQueryClientConfig() *config.CosmwasmConfig { Key: cfg.Key, ChainID: cfg.ChainID, RPCAddr: cfg.RPCAddr, + GRPCAddr: cfg.GRPCAddr, AccountPrefix: cfg.AccountPrefix, KeyringBackend: cfg.KeyringBackend, GasAdjustment: cfg.GasAdjustment, diff --git a/test/e2e/bcd_consumer_integration/clientcontroller/cosmwasm/cosmwasm.go b/test/e2e/bcd_consumer_integration/clientcontroller/cosmwasm/cosmwasm.go index c39e5e29d..07947e5dd 100644 --- a/test/e2e/bcd_consumer_integration/clientcontroller/cosmwasm/cosmwasm.go +++ b/test/e2e/bcd_consumer_integration/clientcontroller/cosmwasm/cosmwasm.go @@ -12,7 +12,12 @@ import ( "context" "encoding/json" "fmt" + "github.com/cosmos/cosmos-sdk/codec" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "math/rand" + "net/url" "sort" "strings" @@ -70,12 +75,12 @@ func NewCosmwasmConsumerController( }, nil } -func (wc *CosmwasmConsumerController) reliablySendMsg(msg sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { - return wc.reliablySendMsgs([]sdk.Msg{msg}, expectedErrs, unrecoverableErrs) +func (cc *CosmwasmConsumerController) reliablySendMsg(msg sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { + return cc.reliablySendMsgs([]sdk.Msg{msg}, expectedErrs, unrecoverableErrs) } -func (wc *CosmwasmConsumerController) reliablySendMsgs(msgs []sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { - return wc.cwClient.ReliablySendMsgs( +func (cc *CosmwasmConsumerController) reliablySendMsgs(msgs []sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { + return cc.cwClient.ReliablySendMsgs( context.Background(), msgs, expectedErrs, @@ -85,7 +90,7 @@ func (wc *CosmwasmConsumerController) reliablySendMsgs(msgs []sdk.Msg, expectedE // CommitPubRandList commits a list of Schnorr public randomness to contract deployed on Consumer Chain // it returns tx hash and error -func (wc *CosmwasmConsumerController) CommitPubRandList( +func (cc *CosmwasmConsumerController) CommitPubRandList( fpPk *btcec.PublicKey, startHeight uint64, numPubRand uint64, @@ -111,7 +116,7 @@ func (wc *CosmwasmConsumerController) CommitPubRandList( return nil, err } - res, err := wc.ExecuteContract(msgBytes) + res, err := cc.ExecuteFinalityContract(msgBytes) if err != nil { return nil, err } @@ -119,20 +124,20 @@ func (wc *CosmwasmConsumerController) CommitPubRandList( return &types.TxResponse{TxHash: res.TxHash}, nil } -func (wc *CosmwasmConsumerController) SubmitFinalitySig( +func (cc *CosmwasmConsumerController) SubmitFinalitySig( fpSK *btcec.PrivateKey, fpBtcPk *btcec.PublicKey, privateRand *eots.PrivateRand, pubRand *bbntypes.SchnorrPubRand, proof *cmtcrypto.Proof, - heightToVote int64, + heightToVote uint64, ) (*types.TxResponse, error) { - block, err := wc.GetCometBlock(heightToVote) + block, err := cc.GetCometBlock(int64(heightToVote)) if err != nil { return nil, err } - msgToSign := append(sdk.Uint64ToBigEndian(uint64(heightToVote)), block.Block.AppHash...) + msgToSign := append(sdk.Uint64ToBigEndian(heightToVote), block.Block.AppHash...) sig, err := eots.Sign(fpSK, privateRand, msgToSign) if err != nil { return nil, err @@ -141,7 +146,7 @@ func (wc *CosmwasmConsumerController) SubmitFinalitySig( submitFinalitySig := &SubmitFinalitySignature{ FpPubkeyHex: bbntypes.NewBIP340PubKeyFromBTCPK(fpBtcPk).MarshalHex(), - Height: uint64(heightToVote), + Height: heightToVote, PubRand: pubRand.MustMarshal(), Proof: Proof{ Total: proof.Total, @@ -162,7 +167,7 @@ func (wc *CosmwasmConsumerController) SubmitFinalitySig( return nil, err } - res, err := wc.ExecuteContract(msgBytes) + res, err := cc.ExecuteFinalityContract(msgBytes) if err != nil { return nil, err } @@ -170,7 +175,7 @@ func (wc *CosmwasmConsumerController) SubmitFinalitySig( return &types.TxResponse{TxHash: res.TxHash, Events: fromCosmosEventsToBytes(res.Events)}, nil } -func (wc *CosmwasmConsumerController) SubmitInvalidFinalitySig( +func (cc *CosmwasmConsumerController) SubmitInvalidFinalitySig( r *rand.Rand, fpSK *btcec.PrivateKey, fpBtcPk *btcec.PublicKey, @@ -210,7 +215,7 @@ func (wc *CosmwasmConsumerController) SubmitInvalidFinalitySig( return nil, err } - res, err := wc.ExecuteContract(msgBytes) + res, err := cc.ExecuteFinalityContract(msgBytes) if err != nil { return nil, err } @@ -219,7 +224,7 @@ func (wc *CosmwasmConsumerController) SubmitInvalidFinalitySig( } // SubmitBatchFinalitySigs submits a batch of finality signatures to Babylon -func (wc *CosmwasmConsumerController) SubmitBatchFinalitySigs( +func (cc *CosmwasmConsumerController) SubmitBatchFinalitySigs( fpPk *btcec.PublicKey, blocks []*types.BlockInfo, pubRandList []*btcec.FieldVal, @@ -255,14 +260,14 @@ func (wc *CosmwasmConsumerController) SubmitBatchFinalitySigs( } execMsg := &wasmdtypes.MsgExecuteContract{ - Sender: wc.cwClient.MustGetAddr(), - Contract: sdk.MustAccAddressFromBech32(wc.cfg.BtcStakingContractAddress).String(), + Sender: cc.cwClient.MustGetAddr(), + Contract: sdk.MustAccAddressFromBech32(cc.cfg.BtcFinalityContractAddress).String(), Msg: msgBytes, } msgs = append(msgs, execMsg) } - res, err := wc.reliablySendMsgs(msgs, nil, nil) + res, err := cc.reliablySendMsgs(msgs, nil, nil) if err != nil { return nil, err } @@ -271,7 +276,7 @@ func (wc *CosmwasmConsumerController) SubmitBatchFinalitySigs( } // QueryFinalityProviderHasPower queries whether the finality provider has voting power at a given height -func (wc *CosmwasmConsumerController) QueryFinalityProviderHasPower( +func (cc *CosmwasmConsumerController) QueryFinalityProviderHasPower( fpPk *btcec.PublicKey, blockHeight uint64, ) (bool, error) { @@ -287,7 +292,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviderHasPower( if err != nil { return false, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return false, err } @@ -301,7 +306,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviderHasPower( return resp.Power > 0, nil } -func (wc *CosmwasmConsumerController) QueryFinalityProviderInfo( +func (cc *CosmwasmConsumerController) QueryFinalityProviderInfo( fpPk *btcec.PublicKey, opts ...uint64, ) (*ConsumerFpInfoResponse, error) { @@ -322,7 +327,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviderInfo( return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -336,7 +341,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviderInfo( return &resp, nil } -func (wc *CosmwasmConsumerController) QueryFinalityProvidersByPower() (*ConsumerFpsByPowerResponse, error) { +func (cc *CosmwasmConsumerController) QueryFinalityProvidersByPower() (*ConsumerFpsByPowerResponse, error) { queryMsgStruct := QueryMsgFinalityProvidersByPower{ FinalityProvidersByPower: struct{}{}, } @@ -346,7 +351,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProvidersByPower() (*Consumer return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -360,10 +365,10 @@ func (wc *CosmwasmConsumerController) QueryFinalityProvidersByPower() (*Consumer return &resp, nil } -func (wc *CosmwasmConsumerController) QueryLatestFinalizedBlock() (*types.BlockInfo, error) { +func (cc *CosmwasmConsumerController) QueryLatestFinalizedBlock() (*types.BlockInfo, error) { isFinalized := true limit := uint64(1) - blocks, err := wc.queryLatestBlocks(nil, &limit, &isFinalized, nil) + blocks, err := cc.queryLatestBlocks(nil, &limit, &isFinalized, nil) if err != nil || len(blocks) == 0 { // do not return error here as FP handles this situation by // not running fast sync @@ -373,12 +378,12 @@ func (wc *CosmwasmConsumerController) QueryLatestFinalizedBlock() (*types.BlockI return blocks[0], nil } -func (wc *CosmwasmConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { - return wc.queryCometBlocksInRange(startHeight, endHeight) +func (cc *CosmwasmConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { + return cc.queryCometBlocksInRange(startHeight, endHeight) } -func (wc *CosmwasmConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { - block, err := wc.cwClient.GetBlock(int64(height)) +func (cc *CosmwasmConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + block, err := cc.cwClient.GetBlock(int64(height)) if err != nil { return nil, err } @@ -389,7 +394,7 @@ func (wc *CosmwasmConsumerController) QueryBlock(height uint64) (*types.BlockInf } // QueryLastPublicRandCommit returns the last public randomness commitments -func (wc *CosmwasmConsumerController) QueryLastPublicRandCommit(fpPk *btcec.PublicKey) (*types.PubRandCommit, error) { +func (cc *CosmwasmConsumerController) QueryLastPublicRandCommit(fpPk *btcec.PublicKey) (*types.PubRandCommit, error) { fpBtcPk := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk) // Construct the query message @@ -405,7 +410,7 @@ func (wc *CosmwasmConsumerController) QueryLastPublicRandCommit(fpPk *btcec.Publ } // Query the smart contract state - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcFinalityContractAddress, string(queryMsgBytes)) if err != nil { return nil, fmt.Errorf("failed to query smart contract state: %w", err) } @@ -428,8 +433,8 @@ func (wc *CosmwasmConsumerController) QueryLastPublicRandCommit(fpPk *btcec.Publ return &commit, nil } -func (wc *CosmwasmConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { - resp, err := wc.QueryIndexedBlock(height) +func (cc *CosmwasmConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { + resp, err := cc.QueryIndexedBlock(height) if err != nil || resp == nil { return false, nil } @@ -437,7 +442,7 @@ func (wc *CosmwasmConsumerController) QueryIsBlockFinalized(height uint64) (bool return resp.Finalized, nil } -func (wc *CosmwasmConsumerController) QueryActivatedHeight() (uint64, error) { +func (cc *CosmwasmConsumerController) QueryActivatedHeight() (uint64, error) { // Construct the query message queryMsg := QueryMsgActivatedHeight{ ActivatedHeight: struct{}{}, @@ -450,7 +455,7 @@ func (wc *CosmwasmConsumerController) QueryActivatedHeight() (uint64, error) { } // Query the smart contract state - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return 0, fmt.Errorf("failed to query smart contract state: %w", err) } @@ -471,15 +476,15 @@ func (wc *CosmwasmConsumerController) QueryActivatedHeight() (uint64, error) { return resp.Height, nil } -func (wc *CosmwasmConsumerController) QueryLatestBlockHeight() (uint64, error) { - block, err := wc.queryCometBestBlock() +func (cc *CosmwasmConsumerController) QueryLatestBlockHeight() (uint64, error) { + block, err := cc.queryCometBestBlock() if err != nil { return 0, err } return block.Height, err } -func (wc *CosmwasmConsumerController) QueryFinalitySignature(fpBtcPkHex string, height uint64) (*FinalitySignatureResponse, error) { +func (cc *CosmwasmConsumerController) QueryFinalitySignature(fpBtcPkHex string, height uint64) (*FinalitySignatureResponse, error) { queryMsgStruct := QueryMsgFinalitySignature{ FinalitySignature: FinalitySignatureQuery{ BtcPkHex: fpBtcPkHex, @@ -491,7 +496,7 @@ func (wc *CosmwasmConsumerController) QueryFinalitySignature(fpBtcPkHex string, return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcFinalityContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -505,7 +510,7 @@ func (wc *CosmwasmConsumerController) QueryFinalitySignature(fpBtcPkHex string, return &resp, nil } -func (wc *CosmwasmConsumerController) QueryFinalityProviders() (*ConsumerFpsResponse, error) { +func (cc *CosmwasmConsumerController) QueryFinalityProviders() (*ConsumerFpsResponse, error) { queryMsgStruct := QueryMsgFinalityProviders{ FinalityProviders: struct{}{}, } @@ -515,7 +520,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviders() (*ConsumerFpsResp return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -529,7 +534,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProviders() (*ConsumerFpsResp return &resp, nil } -func (wc *CosmwasmConsumerController) QueryFinalityProvider(btcPkHex string) (*SingleConsumerFpResponse, error) { +func (cc *CosmwasmConsumerController) QueryFinalityProvider(btcPkHex string) (*SingleConsumerFpResponse, error) { queryMsgStruct := QueryMsgFinalityProvider{ FinalityProvider: FinalityProviderQuery{ BtcPkHex: btcPkHex, @@ -541,7 +546,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProvider(btcPkHex string) (*S return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -555,7 +560,7 @@ func (wc *CosmwasmConsumerController) QueryFinalityProvider(btcPkHex string) (*S return &resp, nil } -func (wc *CosmwasmConsumerController) QueryDelegations() (*ConsumerDelegationsResponse, error) { +func (cc *CosmwasmConsumerController) QueryDelegations() (*ConsumerDelegationsResponse, error) { queryMsgStruct := QueryMsgDelegations{ Delegations: struct{}{}, } @@ -565,7 +570,7 @@ func (wc *CosmwasmConsumerController) QueryDelegations() (*ConsumerDelegationsRe return nil, fmt.Errorf("failed to marshal query message: %v", err) } - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) if err != nil { return nil, err } @@ -579,7 +584,51 @@ func (wc *CosmwasmConsumerController) QueryDelegations() (*ConsumerDelegationsRe return &resp, nil } -func (wc *CosmwasmConsumerController) queryLatestBlocks(startAfter, limit *uint64, finalized, reverse *bool) ([]*types.BlockInfo, error) { +func (cc *CosmwasmConsumerController) QueryStakingContractBalances() (sdk.Coins, error) { + return cc.QueryBalances(cc.cfg.BtcStakingContractAddress) +} + +func (cc *CosmwasmConsumerController) QueryBalance(address string, denom string) (*sdk.Coin, error) { + grpcConn, err := cc.createGrpcConnection() + if err != nil { + return nil, err + } + defer grpcConn.Close() + + // create a gRPC client to query the x/bank service + bankClient := banktypes.NewQueryClient(grpcConn) + bankRes, err := bankClient.Balance( + context.Background(), + &banktypes.QueryBalanceRequest{Address: address, Denom: denom}, + ) + if err != nil { + return nil, err + } + + return bankRes.GetBalance(), nil +} + +// QueryBalances returns balances at the address +func (cc *CosmwasmConsumerController) QueryBalances(address string) (sdk.Coins, error) { + grpcConn, err := cc.createGrpcConnection() + if err != nil { + return nil, err + } + defer grpcConn.Close() + + // create a gRPC client to query the x/bank service. + bankClient := banktypes.NewQueryClient(grpcConn) + bankRes, err := bankClient.AllBalances( + context.Background(), + &banktypes.QueryAllBalancesRequest{Address: address}, + ) + if err != nil { + return nil, err + } + return bankRes.GetBalances(), nil +} + +func (cc *CosmwasmConsumerController) queryLatestBlocks(startAfter, limit *uint64, finalized, reverse *bool) ([]*types.BlockInfo, error) { // Construct the query message queryMsg := QueryMsgBlocks{ Blocks: BlocksQuery{ @@ -597,7 +646,7 @@ func (wc *CosmwasmConsumerController) queryLatestBlocks(startAfter, limit *uint6 } // Query the smart contract state - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcFinalityContractAddress, string(queryMsgBytes)) if err != nil { return nil, fmt.Errorf("failed to query smart contract state: %w", err) } @@ -622,12 +671,12 @@ func (wc *CosmwasmConsumerController) queryLatestBlocks(startAfter, limit *uint6 return blocks, nil } -func (wc *CosmwasmConsumerController) queryCometBestBlock() (*types.BlockInfo, error) { - ctx, cancel := context.WithTimeout(context.Background(), wc.cfg.Timeout) +func (cc *CosmwasmConsumerController) queryCometBestBlock() (*types.BlockInfo, error) { + ctx, cancel := context.WithTimeout(context.Background(), cc.cfg.Timeout) defer cancel() // this will return 20 items at max in the descending order (highest first) - chainInfo, err := wc.cwClient.RPCClient.BlockchainInfo(ctx, 0, 0) + chainInfo, err := cc.cwClient.RPCClient.BlockchainInfo(ctx, 0, 0) if err != nil { return nil, err } @@ -640,12 +689,12 @@ func (wc *CosmwasmConsumerController) queryCometBestBlock() (*types.BlockInfo, e }, nil } -func (wc *CosmwasmConsumerController) queryCometBlocksInRange(startHeight, endHeight uint64) ([]*types.BlockInfo, error) { - ctx, cancel := context.WithTimeout(context.Background(), wc.cfg.Timeout) +func (cc *CosmwasmConsumerController) queryCometBlocksInRange(startHeight, endHeight uint64) ([]*types.BlockInfo, error) { + ctx, cancel := context.WithTimeout(context.Background(), cc.cfg.Timeout) defer cancel() // this will return 20 items at max in the descending order (highest first) - chainInfo, err := wc.cwClient.RPCClient.BlockchainInfo(ctx, int64(startHeight), int64(endHeight)) + chainInfo, err := cc.cwClient.RPCClient.BlockchainInfo(ctx, int64(startHeight), int64(endHeight)) if err != nil { return nil, err } @@ -673,22 +722,37 @@ func (wc *CosmwasmConsumerController) queryCometBlocksInRange(startHeight, endHe return blocks, nil } -func (wc *CosmwasmConsumerController) Close() error { - if !wc.cwClient.IsRunning() { +func (cc *CosmwasmConsumerController) Close() error { + if !cc.cwClient.IsRunning() { return nil } - return wc.cwClient.Stop() + return cc.cwClient.Stop() +} + +func (cc *CosmwasmConsumerController) ExecuteStakingContract(msgBytes []byte) (*provider.RelayerTxResponse, error) { + execMsg := &wasmdtypes.MsgExecuteContract{ + Sender: cc.cwClient.MustGetAddr(), + Contract: cc.cfg.BtcStakingContractAddress, + Msg: msgBytes, + } + + res, err := cc.reliablySendMsg(execMsg, nil, nil) + if err != nil { + return nil, err + } + + return res, nil } -func (wc *CosmwasmConsumerController) ExecuteContract(msgBytes []byte) (*provider.RelayerTxResponse, error) { +func (cc *CosmwasmConsumerController) ExecuteFinalityContract(msgBytes []byte) (*provider.RelayerTxResponse, error) { execMsg := &wasmdtypes.MsgExecuteContract{ - Sender: wc.cwClient.MustGetAddr(), - Contract: wc.cfg.BtcStakingContractAddress, + Sender: cc.cwClient.MustGetAddr(), + Contract: cc.cfg.BtcFinalityContractAddress, Msg: msgBytes, } - res, err := wc.reliablySendMsg(execMsg, nil, nil) + res, err := cc.reliablySendMsg(execMsg, nil, nil) if err != nil { return nil, err } @@ -698,61 +762,67 @@ func (wc *CosmwasmConsumerController) ExecuteContract(msgBytes []byte) (*provide // QuerySmartContractState queries the smart contract state // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) QuerySmartContractState(contractAddress string, queryData string) (*wasmdtypes.QuerySmartContractStateResponse, error) { - return wc.cwClient.QuerySmartContractState(contractAddress, queryData) +func (cc *CosmwasmConsumerController) QuerySmartContractState(contractAddress string, queryData string) (*wasmdtypes.QuerySmartContractStateResponse, error) { + return cc.cwClient.QuerySmartContractState(contractAddress, queryData) } // StoreWasmCode stores the wasm code on the consumer chain // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) StoreWasmCode(wasmFile string) error { - return wc.cwClient.StoreWasmCode(wasmFile) +func (cc *CosmwasmConsumerController) StoreWasmCode(wasmFile string) error { + return cc.cwClient.StoreWasmCode(wasmFile) } // InstantiateContract instantiates a contract with the given code id and init msg // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) InstantiateContract(codeID uint64, initMsg []byte) error { - return wc.cwClient.InstantiateContract(codeID, initMsg) +func (cc *CosmwasmConsumerController) InstantiateContract(codeID uint64, initMsg []byte) error { + return cc.cwClient.InstantiateContract(codeID, initMsg) } // GetLatestCodeId returns the latest wasm code id. // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) GetLatestCodeId() (uint64, error) { - return wc.cwClient.GetLatestCodeId() +func (cc *CosmwasmConsumerController) GetLatestCodeId() (uint64, error) { + return cc.cwClient.GetLatestCodeId() } // ListContractsByCode lists all contracts by wasm code id // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) ListContractsByCode(codeID uint64, pagination *sdkquerytypes.PageRequest) (*wasmdtypes.QueryContractsByCodeResponse, error) { - return wc.cwClient.ListContractsByCode(codeID, pagination) +func (cc *CosmwasmConsumerController) ListContractsByCode(codeID uint64, pagination *sdkquerytypes.PageRequest) (*wasmdtypes.QueryContractsByCodeResponse, error) { + return cc.cwClient.ListContractsByCode(codeID, pagination) } // SetBtcStakingContractAddress updates the BtcStakingContractAddress in the configuration // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) SetBtcStakingContractAddress(newAddress string) { - wc.cfg.BtcStakingContractAddress = newAddress +func (cc *CosmwasmConsumerController) SetBtcStakingContractAddress(newAddress string) { + cc.cfg.BtcStakingContractAddress = newAddress +} + +// SetBtcFinalityContractAddress updates the BtcFinalityContractAddress in the configuration +// NOTE: this function is only meant to be used in tests. +func (cc *CosmwasmConsumerController) SetBtcFinalityContractAddress(newAddress string) { + cc.cfg.BtcFinalityContractAddress = newAddress } // MustGetValidatorAddress gets the validator address of the consumer chain // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) MustGetValidatorAddress() string { - return wc.cwClient.MustGetAddr() +func (cc *CosmwasmConsumerController) MustGetValidatorAddress() string { + return cc.cwClient.MustGetAddr() } // GetCometNodeStatus gets the tendermint node status of the consumer chain // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) GetCometNodeStatus() (*coretypes.ResultStatus, error) { - return wc.cwClient.GetStatus() +func (cc *CosmwasmConsumerController) GetCometNodeStatus() (*coretypes.ResultStatus, error) { + return cc.cwClient.GetStatus() } // GetCometBlock gets the tendermint block at a given height // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) GetCometBlock(height int64) (*coretypes.ResultBlock, error) { - return wc.cwClient.GetBlock(height) +func (cc *CosmwasmConsumerController) GetCometBlock(height int64) (*coretypes.ResultBlock, error) { + return cc.cwClient.GetBlock(height) } // QueryIndexedBlock queries the indexed block at a given height // NOTE: this function is only meant to be used in tests. -func (wc *CosmwasmConsumerController) QueryIndexedBlock(height uint64) (*IndexedBlock, error) { +func (cc *CosmwasmConsumerController) QueryIndexedBlock(height uint64) (*IndexedBlock, error) { // Construct the query message queryMsgStruct := QueryMsgBlock{ Block: BlockQuery{ @@ -765,7 +835,7 @@ func (wc *CosmwasmConsumerController) QueryIndexedBlock(height uint64) (*Indexed } // Query the smart contract state - dataFromContract, err := wc.QuerySmartContractState(wc.cfg.BtcStakingContractAddress, string(queryMsgBytes)) + dataFromContract, err := cc.QuerySmartContractState(cc.cfg.BtcFinalityContractAddress, string(queryMsgBytes)) if err != nil { return nil, fmt.Errorf("failed to query smart contract state: %w", err) } @@ -825,3 +895,23 @@ func (cc *CosmwasmConsumerController) QueryNextSequenceReceive(channelID, portID func (cc *CosmwasmConsumerController) IBCChannels() (*channeltypes.QueryChannelsResponse, error) { return cc.cwClient.IBCChannels() } + +func (cc *CosmwasmConsumerController) createGrpcConnection() (*grpc.ClientConn, error) { + // Create a connection to the gRPC server. + parsedUrl, err := url.Parse(cc.cfg.GRPCAddr) + if err != nil { + return nil, fmt.Errorf("grpc-address is not correctly formatted: %w", err) + } + endpoint := fmt.Sprintf("%s:%s", parsedUrl.Hostname(), parsedUrl.Port()) + grpcConn, err := grpc.NewClient( + endpoint, + grpc.WithTransportCredentials(insecure.NewCredentials()), // The Cosmos SDK doesn't support any transport security mechanism. + // This instantiates a general gRPC codec which handles proto bytes. We pass in a nil interface registry + // if the request/response types contain interface instead of 'nil' you should pass the application specific codec. + grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())), + ) + if err != nil { + return nil, err + } + return grpcConn, nil +} diff --git a/test/e2e/bcd_consumer_integration_test.go b/test/e2e/bcd_consumer_integration_test.go index 92c0ebb4e..c15f20114 100644 --- a/test/e2e/bcd_consumer_integration_test.go +++ b/test/e2e/bcd_consumer_integration_test.go @@ -49,6 +49,8 @@ var ( // TODO: get consumer id from ibc client-state query consumerID = "07-tendermint-0" + czFpBTCSK *btcec.PrivateKey + czFpBTCPK *btcec.PublicKey czDelBtcSk, czDelBtcPk, _ = datagen.GenRandomBTCKeyPair(r) ) @@ -136,7 +138,11 @@ func (s *BCDConsumerIntegrationTestSuite) Test3CreateConsumerFinalityProvider() numConsumerFPs := datagen.RandomInt(r, 5) + 1 var consumerFps []*bstypes.FinalityProvider for i := 0; i < int(numConsumerFPs); i++ { - consumerFp, _, _ := s.createVerifyConsumerFP() + consumerFp, SK, PK := s.createVerifyConsumerFP() + if i == 0 { + czFpBTCSK = SK + czFpBTCPK = PK + } consumerFps = append(consumerFps, consumerFp) } @@ -262,14 +268,83 @@ func (s *BCDConsumerIntegrationTestSuite) Test5ActivateDelegation() { }, time.Minute, time.Second*5) } -// Test6BabylonFPCascadedSlashing +func (s *BCDConsumerIntegrationTestSuite) Test6ConsumerFPRewardsGeneration() { + // Get the activated block height and block on the consumer chain + czActivatedHeight, err := s.cosmwasmController.QueryActivatedHeight() + s.NoError(err) + czActivatedBlock, err := s.cosmwasmController.QueryIndexedBlock(czActivatedHeight) + s.NoError(err) + s.NotNil(czActivatedBlock) + + // Ensure the staking contract balance is initially empty + rewards, err := s.cosmwasmController.QueryStakingContractBalances() + s.NoError(err) + s.Empty(rewards) + + // Commit public randomness at the activated block height on the consumer chain + randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, czFpBTCSK, uint64(czActivatedHeight), 100) + s.NoError(err) + + // Submit the public randomness to the consumer chain + txResp, err := s.cosmwasmController.CommitPubRandList(czFpBTCPK, uint64(czActivatedHeight), 100, randListInfo.Commitment, msgCommitPubRandList.Sig.MustToBTCSig()) + s.NoError(err) + s.NotNil(txResp) + + // Consumer finality provider submits finality signature + txResp, err = s.cosmwasmController.SubmitFinalitySig( + czFpBTCSK, + czFpBTCPK, + randListInfo.SRList[0], + &randListInfo.PRList[0], + randListInfo.ProofList[0].ToProto(), + czActivatedHeight, + ) + s.NoError(err) + s.NotNil(txResp) + + // Ensure consumer finality provider's finality signature is received and stored in the smart contract + s.Eventually(func() bool { + fpSigsResponse, err := s.cosmwasmController.QueryFinalitySignature(bbntypes.NewBIP340PubKeyFromBTCPK(czFpBTCPK).MarshalHex(), uint64(czActivatedHeight)) + if err != nil { + s.T().Logf("failed to query finality signature: %s", err.Error()) + return false + } + if fpSigsResponse == nil || fpSigsResponse.Signature == nil || len(fpSigsResponse.Signature) == 0 { + return false + } + return true + }, time.Minute, time.Second*5) + + // Once the vote is cast, ensure the block is finalised + finalizedBlock, err := s.cosmwasmController.QueryIndexedBlock(uint64(czActivatedHeight)) + s.NoError(err) + s.NotEmpty(finalizedBlock) + s.Equal(hex.EncodeToString(finalizedBlock.AppHash), hex.EncodeToString(czActivatedBlock.AppHash)) + s.True(finalizedBlock.Finalized) + + // Ensure consumer rewards are generated and sent to the staking contract + s.Eventually(func() bool { + rewards, err := s.cosmwasmController.QueryStakingContractBalances() + if err != nil { + s.T().Logf("failed to query rewards: %s", err.Error()) + return false + } + if len(rewards) == 0 { + return false + } + fmt.Println("Consumer rewards: ", rewards) + return true + }, time.Minute, time.Second*5) +} + +// Test7BabylonFPCascadedSlashing // 1. Submits a Babylon FP valid finality sig to Babylon // 2. Block is finalized. // 3. Equivocates/ Submits a invalid finality sig to Babylon // 4. Babylon FP is slashed // 4. Babylon notifies involved consumer about the delegations. // 5. Consumer discounts the voting power of other involved consumer FP's in the affected delegations -func (s *BCDConsumerIntegrationTestSuite) Test6BabylonFPCascadedSlashing() { +func (s *BCDConsumerIntegrationTestSuite) Test7BabylonFPCascadedSlashing() { // get the activated height activatedHeight, err := s.babylonController.QueryActivatedHeight() s.NoError(err) @@ -362,9 +437,9 @@ func (s *BCDConsumerIntegrationTestSuite) Test6BabylonFPCascadedSlashing() { }, time.Minute, time.Second*5) } -func (s *BCDConsumerIntegrationTestSuite) Test7ConsumerFPCascadedSlashing() { +func (s *BCDConsumerIntegrationTestSuite) Test8ConsumerFPCascadedSlashing() { // create a new consumer finality provider - resp, czFpBTCSK, czFpBTCPK := s.createVerifyConsumerFP() + resp, czFpBTCSK2, czFpBTCPK2 := s.createVerifyConsumerFP() consumerFp, err := s.babylonController.QueryConsumerFinalityProvider(consumerID, resp.BtcPk.MarshalHex()) s.NoError(err) @@ -411,22 +486,22 @@ func (s *BCDConsumerIntegrationTestSuite) Test7ConsumerFPCascadedSlashing() { s.NotNil(czLatestBlock) // commit public randomness at the latest block height on the consumer chain - randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, czFpBTCSK, uint64(czlatestBlockHeight), 100) + randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, czFpBTCSK2, uint64(czlatestBlockHeight), 100) s.NoError(err) // submit the public randomness to the consumer chain - txResp, err := s.cosmwasmController.CommitPubRandList(czFpBTCPK, uint64(czlatestBlockHeight), 100, randListInfo.Commitment, msgCommitPubRandList.Sig.MustToBTCSig()) + txResp, err := s.cosmwasmController.CommitPubRandList(czFpBTCPK2, uint64(czlatestBlockHeight), 100, randListInfo.Commitment, msgCommitPubRandList.Sig.MustToBTCSig()) s.NoError(err) s.NotNil(txResp) // consumer finality provider submits finality signature txResp, err = s.cosmwasmController.SubmitFinalitySig( - czFpBTCSK, - czFpBTCPK, + czFpBTCSK2, + czFpBTCPK2, randListInfo.SRList[0], &randListInfo.PRList[0], randListInfo.ProofList[0].ToProto(), - czlatestBlockHeight, + uint64(czlatestBlockHeight), ) s.NoError(err) s.NotNil(txResp) @@ -447,8 +522,8 @@ func (s *BCDConsumerIntegrationTestSuite) Test7ConsumerFPCascadedSlashing() { // consumer finality provider submits invalid finality signature txResp, err = s.cosmwasmController.SubmitInvalidFinalitySig( r, - czFpBTCSK, - czFpBTCPK, + czFpBTCSK2, + czFpBTCPK2, randListInfo.SRList[0], &randListInfo.PRList[0], randListInfo.ProofList[0].ToProto(), @@ -817,12 +892,12 @@ func (s *BCDConsumerIntegrationTestSuite) createVerifyConsumerFP() (*bstypes.Fin create a random consumer finality provider on Babylon */ // NOTE: we use the node's secret key as Babylon secret key for the finality provider - czFpBTCSK, czFpBTCPK, _ := datagen.GenRandomBTCKeyPair(r) + czFpBTCSecretKey, czFpBTCPublicKey, _ := datagen.GenRandomBTCKeyPair(r) sdk.SetAddrCacheEnabled(false) bbnparams.SetAddressPrefixes() fpBabylonAddr, err := sdk.AccAddressFromBech32(s.babylonController.MustGetTxSigner()) s.NoError(err) - czFp, err := datagen.GenCustomFinalityProvider(r, czFpBTCSK, fpBabylonAddr, consumerID) + czFp, err := datagen.GenCustomFinalityProvider(r, czFpBTCSecretKey, fpBabylonAddr, consumerID) s.NoError(err) czFp.Commission = &minCommissionRate czFpPop, err := czFp.Pop.Marshal() @@ -849,7 +924,7 @@ func (s *BCDConsumerIntegrationTestSuite) createVerifyConsumerFP() (*bstypes.Fin s.Equal(czFp.SlashedBabylonHeight, actualFp.SlashedBabylonHeight) s.Equal(czFp.SlashedBtcHeight, actualFp.SlashedBtcHeight) s.Equal(consumerID, actualFp.ConsumerId) - return czFp, czFpBTCSK, czFpBTCPK + return czFp, czFpBTCSecretKey, czFpBTCPublicKey } // helper function: initBabylonController initializes the Babylon controller with the default configuration. @@ -891,6 +966,7 @@ func (s *BCDConsumerIntegrationTestSuite) initCosmwasmController() error { } cfg.BtcStakingContractAddress = "bbnc1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqgn0kq0" + cfg.BtcFinalityContractAddress = "bbnc17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgssg3nft" cfg.ChainID = "bcd-test" cfg.KeyDirectory = filepath.Join(currentDir, "../../contrib/images/ibcsim-bcd/.testnets/bcd/bcd-test") cfg.AccountPrefix = "bbnc" diff --git a/test/e2e/bytecode/babylon_contract.wasm b/test/e2e/bytecode/babylon_contract.wasm index f0ad59d84..e208b4d59 100644 Binary files a/test/e2e/bytecode/babylon_contract.wasm and b/test/e2e/bytecode/babylon_contract.wasm differ diff --git a/test/e2e/bytecode/btc_finality.wasm b/test/e2e/bytecode/btc_finality.wasm new file mode 100644 index 000000000..a7e12e76a Binary files /dev/null and b/test/e2e/bytecode/btc_finality.wasm differ diff --git a/test/e2e/bytecode/btc_staking.wasm b/test/e2e/bytecode/btc_staking.wasm index 100b5b767..49b64febc 100644 Binary files a/test/e2e/bytecode/btc_staking.wasm and b/test/e2e/bytecode/btc_staking.wasm differ diff --git a/test/e2e/bytecode/version.txt b/test/e2e/bytecode/version.txt index 70e5b8a1e..f1a860651 100644 --- a/test/e2e/bytecode/version.txt +++ b/test/e2e/bytecode/version.txt @@ -1 +1 @@ -83b50960127b95986fa81f61dfbdf39832259b99 \ No newline at end of file +v0.11.0-rc.1 diff --git a/test/e2e/ibc_transfer_e2e_test.go b/test/e2e/ibc_transfer_e2e_test.go index 60f29d237..fed4e4a6a 100644 --- a/test/e2e/ibc_transfer_e2e_test.go +++ b/test/e2e/ibc_transfer_e2e_test.go @@ -153,7 +153,7 @@ func (s *IBCTransferTestSuite) Test2IBCTransferBack() { } return math.Abs(float64(balanceB.Sub(transferCoin).AmountOf(denom).Int64()- balanceB2.AmountOf(denom).Int64())) < delta - }, 10*time.Second, 1*time.Second, "Transfer back was not successful") + }, 15*time.Second, 1*time.Second, "Transfer back A was not successful") nativeCoin := sdk.NewInt64Coin(nativeDenom, amount) s.Require().Eventually(func() bool { @@ -168,5 +168,5 @@ func (s *IBCTransferTestSuite) Test2IBCTransferBack() { // Check that the balance of the native denom has increased return math.Abs(float64(balanceA.Add(nativeCoin).AmountOf(nativeDenom).Int64()- balanceA2.AmountOf(nativeDenom).Int64())) < delta - }, 10*time.Second, 1*time.Second, "Transfer back was not successful") + }, 15*time.Second, 1*time.Second, "Transfer back B was not successful") } diff --git a/test/e2e/scripts/copy_local_wasm.sh b/test/e2e/scripts/copy_local_wasm.sh index 3ce31fdcb..7a2d9552a 100755 --- a/test/e2e/scripts/copy_local_wasm.sh +++ b/test/e2e/scripts/copy_local_wasm.sh @@ -2,7 +2,7 @@ set -o errexit -o nounset -o pipefail command -v shellcheck >/dev/null && shellcheck "$0" -CONTRACTS="babylon_contract btc_staking" +CONTRACTS="babylon_contract btc_staking btc_finality" OUTPUT_FOLDER="$(dirname "$0")/../bytecode" echo "DEV-only: copy from local built instead of downloading" diff --git a/test/e2e/scripts/download_release.sh b/test/e2e/scripts/download_release.sh index 20c9fda43..8801874ec 100755 --- a/test/e2e/scripts/download_release.sh +++ b/test/e2e/scripts/download_release.sh @@ -1,44 +1,25 @@ #!/bin/bash -set -o nounset -o pipefail +set -o errexit -o nounset -o pipefail command -v shellcheck >/dev/null && shellcheck "$0" OWNER="babylonlabs-io" REPO="babylon-contract" -CONTRACTS="babylon_contract btc_staking" +CONTRACTS="babylon_contract btc_staking btc_finality" OUTPUT_FOLDER="$(dirname "$0")/../bytecode" -[ -z "$GITHUB_API_TOKEN" ] && echo "Error: Please define GITHUB_API_TOKEN variable." >&2 && exit 1 - [ $# -ne 1 ] && echo "Usage: $0 " && exit 1 -type curl >&2 +type wget >&2 TAG="$1" -GH_API="https://api.github.com" -GH_REPO="$GH_API/repos/$OWNER/$REPO" -GH_TAGS="$GH_REPO/releases/tags/$TAG" -AUTH="Authorization: token $GITHUB_API_TOKEN" - -# Validate token -curl -o /dev/null -sH "$AUTH" $GH_REPO || { - echo "Error: Invalid repo, token or network issue!" - exit 1 -} - -# Read asset tags -RESPONSE=$(curl -sH "$AUTH" "$GH_TAGS") - for CONTRACT in $CONTRACTS do - # Get id of the contract - ID=$(echo "$RESPONSE" | grep -C3 "name.:.\+$CONTRACT.wasm" | grep -w id | cut -f1 -d, | awk '{print $2}') - - [ -z "$ID" ] && echo "Error: Failed to get asset id, response: $RESPONSE" | awk 'length($0)<100' >&2 && exit 1 - GH_ASSET="$GH_REPO/releases/assets/$ID" - - # Download asset file echo -n "Downloading $CONTRACT..." >&2 - curl -s -L -H "Authorization: token $GITHUB_API_TOKEN" -H 'Accept: application/octet-stream' "$GH_ASSET" >"$OUTPUT_FOLDER/$CONTRACT.wasm" - echo "$TAG" >"$OUTPUT_FOLDER/version.txt" + FILE="$CONTRACT.wasm.zip" + URL="https://github.com/$OWNER/$REPO/releases/download/$TAG/$FILE" + wget -nv -O "$OUTPUT_FOLDER/$FILE" "$URL" + unzip -p "$OUTPUT_FOLDER/$FILE" >"$OUTPUT_FOLDER/$CONTRACT.wasm" + rm -f "$OUTPUT_FOLDER/$FILE" echo "done." >&2 done +echo "$TAG" >"$OUTPUT_FOLDER/version.txt"