Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ADR-024): Enable BTC-timestamping public randomness #37

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/

# Primary repo maintainers
* @babylonlabs-io/core-dev

1 change: 0 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,6 @@ func NewBabylonApp(

app.AppKeepers.InitKeepers(
logger,
appCodec,
&btcConfig,
encCfg,
bApp,
Expand Down
14 changes: 12 additions & 2 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,12 @@ type AppKeepers struct {
keys map[string]*storetypes.KVStoreKey
tkeys map[string]*storetypes.TransientStoreKey
memKeys map[string]*storetypes.MemoryStoreKey

EncCfg *appparams.EncodingConfig
}

func (ak *AppKeepers) InitKeepers(
logger log.Logger,
appCodec codec.Codec,
btcConfig *bbn.BtcConfig,
encodingConfig *appparams.EncodingConfig,
bApp *baseapp.BaseApp,
Expand All @@ -176,6 +177,9 @@ func (ak *AppKeepers) InitKeepers(
powLimit := btcConfig.PowLimit()
btcNetParams := btcConfig.NetParams()

ak.EncCfg = encodingConfig
appCodec := encodingConfig.Codec

// set persistent store keys
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey,
Expand Down Expand Up @@ -524,7 +528,9 @@ func (ak *AppKeepers) InitKeepers(
runtime.NewKVStoreService(keys[btcstakingtypes.StoreKey]),
&btclightclientKeeper,
&btcCheckpointKeeper,
&checkpointingKeeper,
// setting the finality keeper as nil for now
// need to set it after finality keeper is initiated
nil,
btcNetParams,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
Expand All @@ -535,10 +541,14 @@ func (ak *AppKeepers) InitKeepers(
runtime.NewKVStoreService(keys[finalitytypes.StoreKey]),
ak.BTCStakingKeeper,
ak.IncentiveKeeper,
ak.CheckpointingKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
ak.BTCStakingKeeper = *ak.BTCStakingKeeper.SetHooks(btcstakingtypes.NewMultiBtcStakingHooks(ak.FinalityKeeper.Hooks()))
ak.FinalityKeeper = *ak.FinalityKeeper.SetHooks(finalitytypes.NewMultiFinalityHooks(ak.BTCStakingKeeper.Hooks()))
// TODO this introduces circular dependency between the finality module and
// the btcstaking modules, need refactoring
ak.BTCStakingKeeper.FinalityKeeper = ak.FinalityKeeper

// create evidence keeper with router
evidenceKeeper := evidencekeeper.NewKeeper(
Expand Down
55 changes: 55 additions & 0 deletions app/upgrades/signetlaunch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,58 @@

This folder contains a software upgrade for testing purposes.
DO NOT USE IN PRODUCTION!

## Compile signet launch upgrade

This upgrade loads 2 JSONs from strings in different files.
BTC Headers from `./data_btc_headers.go` and signed messages
to create finality providers `./data_signed_fps.go`.

### BTC Headers

This upgrade accepts insertion of multiple
[`btclighttypes.BTCHeaderInfo`](../../../x/btclightclient/types/btclightclient.pb.go#36)
due to Babylon Phase-1 and Phase-2 launch will be a few months appart, so
during Phase-1 Babylon accepts BTC delegations without Babylonchain running.
At the time of launching the Babylonchain it is needed all the BTC block
headers that has passed since babylon started to accept BTC staking messages,
and to avoid giving too much work for
[vigilante](https://github.com/babylonlabs-io/vigilante)
to submit all of those missing headers.

To generate this BTC headers there is a specific command in
[staking-indexer](https://github.com/babylonlabs-io/staking-indexer)
that query BTC for all the BTC headers and outputs it as json file
`sid btc-headers [from-block-height] [to-block-height]` and then
it is needed to recreate the golang file `./data_btc_headers.go`
with some simple bash script:

```shell
GO_BTC_HEADERS_PATH="signetlaunch/data_btc_headers.go"
EXPORT_TO="./btc-headers.json"
# export the btc headers to a file
$SID_BIN btc-headers 1 1000 --output $EXPORT_TO
btcHeadersJson=$(cat $EXPORT_TO)

# writes the headers to babylon as go file
echo "package signetlaunch

const NewBtcHeadersStr = \`$btcHeadersJson\`" > $GO_BTC_HEADERS_PATH
```

### Signed Create Finality Provider

For BTC stakers to stake during Phase-1 it is needed to have finality
providers. Babylon created a repository to publicly store this information
inside [networks](https://github.com/babylonlabs-io/networks) repository.
Inside the bbn-1 mainnet all the finality providers that wanted to be available
for BTC staking since the beginning would need to
[register](https://github.com/babylonlabs-io/networks/blob/main/bbn-1/finality-providers/README.md)
theirselves in the registry.
For the transition from Phase-1 to Phase-2, registered finality providers in
Phase-1 will need to provider a signed
[MsgCreateFinalityProvider](../../../x/btcstaking/types/tx.pb.go#38) as a
json file message inside the networks repository registry.

<!-- TODO: shell to generate the string message with signed finality
providers from the networks repository -->
122 changes: 122 additions & 0 deletions app/upgrades/signetlaunch/data_signed_fps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package signetlaunch

const SignedFPsStr = `{
"signed_txs_create_fp": [
{
"body": {
"messages": [
{
"@type": "/babylon.btcstaking.v1.MsgCreateFinalityProvider",
"addr": "bbn1gwecky0m842kvjg7mcvt9z330rz96948aplqlm",
"description": {
"moniker": "fp-1",
"identity": "",
"website": "fp1.com.br",
"security_contact": "[email protected]",
"details": "best-fp-1"
},
"commission": "0.050000000000000000",
"btc_pk": "a94eef36ea7c596ba01b2018d55c202ebd8a82a0baf1a435818bc524bfd4e10a",
"pop": {
"btc_sig_type": "BIP340",
"btc_sig": "q5aykrV4imao9kiIVvWhBf8hPbIQW7GbdnDDCAZQRyCm4ZBaUiAGO3oFbEgVeLKNAd0xGmcCAJSbXu0OrpcQkQ=="
}
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A9XXtGMjEFgavPv7GHo5rbI/XulwA0Hn2xlzsdCRDCTl"
},
"mode_info": {
"single": {
"mode": "SIGN_MODE_DIRECT"
}
},
"sequence": "0"
}
],
"fee": {
"amount": [
{
"denom": "ubbn",
"amount": "2000000"
}
],
"gas_limit": "200000",
"payer": "",
"granter": ""
},
"tip": null
},
"signatures": [
"8wQGbPM5Xc5PmrynGmxbslqSA6tFW/5Vgg9sVZZ1WWsRTR5m040t2wgR+BjUrLNnO+JtrDlb38Su4XFSR76b9Q=="
]
},
{
"body": {
"messages": [
{
"@type": "/babylon.btcstaking.v1.MsgCreateFinalityProvider",
"addr": "bbn1mwwywrmynkf0n5maps6yrtvgx2qqh3mlccdg6g",
"description": {
"moniker": "fp-2",
"identity": "",
"website": "fp2.com.br",
"security_contact": "[email protected]",
"details": "best-fp-2"
},
"commission": "0.100000000000000000",
"btc_pk": "bae0f3bfedc4de9e776fcbbb4b1dbae2641193fc20527ffc0a728968ebcd2d95",
"pop": {
"btc_sig_type": "BIP340",
"btc_sig": "IFU+77I8e7VOGudJdN5kk/8Hs2Biqiiw+sejBbYrtPRSNhFRhFrxhOru5kYHPxZ2XwadlfZfZjmXB8Uvj/hb5w=="
}
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A3XkUtvcp3DnAvDKN4zYkES3xc6wi83LQBeAAlNG3Ebl"
},
"mode_info": {
"single": {
"mode": "SIGN_MODE_DIRECT"
}
},
"sequence": "0"
}
],
"fee": {
"amount": [
{
"denom": "ubbn",
"amount": "2000000"
}
],
"gas_limit": "200000",
"payer": "",
"granter": ""
},
"tip": null
},
"signatures": [
"QMpALwCa+mHtKRv9Jg9RyHg/lOnFNa5i09tHgHgSuwh8JbNalYy4v2bTZ2PGDUh0JZCPUMeO487WacZofVhl9g=="
]
}
]
}`
113 changes: 113 additions & 0 deletions app/upgrades/signetlaunch/data_signed_fps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package signetlaunch_test

import (
"bytes"
"encoding/json"
"testing"
"time"

"github.com/babylonlabs-io/babylon/app"
v1 "github.com/babylonlabs-io/babylon/app/upgrades/signetlaunch"
btcstktypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
"github.com/stretchr/testify/require"
)

func TestValidateSignatureSignedFPsFromData(t *testing.T) {
bbnApp := app.NewTmpBabylonApp()
cdc := bbnApp.AppCodec()
// the chain ID in context needs to match the one used when creating the tx signature.
chainID := "bbn-1"

ctx := bbnApp.BaseApp.NewContextLegacy(true, tmproto.Header{Height: 1, ChainID: chainID, Time: time.Now().UTC()})
buff := bytes.NewBufferString(v1.SignedFPsStr)
simulateTx := false

var d v1.DataSignedFps
err := json.Unmarshal(buff.Bytes(), &d)
require.NoError(t, err)

antehandlerSigVerifier := buildAnteHandlerSigVerifier(t, bbnApp)

fpAddrs := make(map[string]interface{}, len(d.SignedTxsFP))
for _, txAny := range d.SignedTxsFP {
txBytes, err := json.Marshal(txAny)
require.NoError(t, err)

// decodes the transaction
tx, err := bbnApp.TxConfig().TxJSONDecoder()(txBytes)
require.NoError(t, err)

msgs := tx.GetMsgs()
require.Len(t, msgs, 1)

msg, ok := msgs[0].(*btcstktypes.MsgCreateFinalityProvider)
require.True(t, ok)

_, exist := fpAddrs[msg.Addr]
require.False(t, exist)
fpAddrs[msg.Addr] = nil

require.NoError(t, msg.ValidateBasic())

// loads messages from the tx, only one message per tx is allowed.
msgsV2, err := tx.GetMsgsV2()
require.NoError(t, err)
require.Len(t, msgsV2, 1)

msgV2 := msgsV2[0]
signers, err := cdc.GetMsgV2Signers(msgV2)
require.NoError(t, err)
require.Len(t, signers, 1)

// checks that the signer_infos corresponding address in the transaction
// matches the FP address defined.
signerAddrStr, err := cdc.InterfaceRegistry().SigningContext().AddressCodec().BytesToString(signers[0])
require.NoError(t, err)

signerBbnAddr, err := sdk.AccAddressFromBech32(signerAddrStr)
require.NoError(t, err)

require.Equal(t, msg.Addr, signerAddrStr)
// Proof of Possession check only for type BIP340 as expected in the networks registry instructions
require.NoError(t, msg.Pop.VerifyBIP340(signerBbnAddr, msg.BtcPk))

// creates the account with the signer address and sets the
// sequence and acc number to zero every time, for this reason
// it needs to remove account right after, otherwise new accounts
// would have account number +1 and the signature verification would fail.
acc := bbnApp.AccountKeeper.NewAccountWithAddress(ctx, signerBbnAddr)
require.NoError(t, acc.SetSequence(0))
require.NoError(t, acc.SetAccountNumber(0))
bbnApp.AccountKeeper.SetAccount(ctx, acc)

_, err = antehandlerSigVerifier(ctx, tx, simulateTx)
require.NoError(t, err)

bbnApp.AccountKeeper.RemoveAccount(ctx, acc)
}
}

func buildAnteHandlerSigVerifier(t *testing.T, bbnApp *app.BabylonApp) sdk.AnteHandler {
cdc := bbnApp.AppCodec()

txConfigOpts := authtx.ConfigOptions{
TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(bbnApp.GetBankKeeper()),
EnabledSignModes: []signing.SignMode{signing.SignMode_SIGN_MODE_DIRECT},
}
anteTxConfig, err := authtx.NewTxConfigWithOptions(
codec.NewProtoCodec(cdc.InterfaceRegistry()),
txConfigOpts,
)
require.NoError(t, err)

svd := ante.NewSigVerificationDecorator(bbnApp.AppKeepers.AccountKeeper, anteTxConfig.SignModeHandler())
spkd := ante.NewSetPubKeyDecorator(bbnApp.AppKeepers.AccountKeeper)
return sdk.ChainAnteDecorators(spkd, svd)
}
Loading
Loading