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

zoneconcierge: enriching SubmissionData to store BTCSpvProof #239

Merged
merged 18 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from 11 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
45 changes: 39 additions & 6 deletions proto/babylon/btccheckpoint/btccheckpoint.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,40 @@ import "gogoproto/gogo.proto";

option go_package = "github.com/babylonchain/babylon/x/btccheckpoint/types";

// Consider we have a Merkle tree with following structure:
// ROOT
// / \
// H1234 H5555
// / \ \
// H12 H34 H55
// / \ / \ /
// H1 H2 H3 H4 H5
// L1 L2 L3 L4 L5
// To prove L3 was part of ROOT we need:
// - btc_transaction_index = 2 which in binary is 010
// (where 0 means going left, 1 means going right in the tree)
// - merkle_nodes we'd have H4 || H12 || H5555
// By looking at 010 we would know that H4 is a right sibling,
// H12 is left, H5555 is right again.
message BTCSpvProof {
// Valid bitcoin transaction containing OP_RETURN opcode.
bytes btc_transaction = 1;
// Index of transaction within the block. Index is needed to determine if
// currently hashed node is left or right.
uint32 btc_transaction_index = 2;
// List of concatenated intermediate merkle tree nodes, without root node and
// leaf node against which we calculate the proof. Each node has 32 byte
// length. Example proof can look like: 32_bytes_of_node1 || 32_bytes_of_node2
// || 32_bytes_of_node3 so the length of the proof will always be divisible
// by 32.
bytes merkle_nodes = 3;
// Valid btc header which confirms btc_transaction.
// Should have exactly 80 bytes
bytes confirming_btc_header = 4
[ (gogoproto.customtype) =
"github.com/babylonchain/babylon/types.BTCHeaderBytes" ];
}

// Each provided OP_RETURN transaction can be idendtified by hash of block in
// which transaction was included and transaction index in the block
message TransactionKey {
Expand Down Expand Up @@ -49,12 +83,11 @@ message SubmissionData {
// Address of submitter of given checkpoint. Required to payup the reward to
// submitter of given checkpoint
bytes submitter = 1;
// Required to recover address of sender of btc transction to payup the reward.
// TODO: Maybe it is worth recovering senders while processing the InsertProof
// message, and store only those. Another point is that it is not that simple
// to recover sender of btc tx.
repeated bytes btctransaction = 2;

// proofs is the two `BTCSpvProof`s corresponding to the submission
// It is used for
// - recovering address of sender of btc transction to payup the reward.
// - allowing the ZoneConcierge module to prove the checkpoint is submitted to BTC
repeated BTCSpvProof proofs = 2;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two problems I see with sticking BTCSpvProof verbatim into SubmissionData.

  1. It creates coupling between stuff we receive from outside world (as BTCSpvProof is part of message MsgInsertBTCSpvProof) and between stuff we have already validated and saved into database. Now if we want to change BTCSpvProof due to some message requirements we will also modify it in db or if we want to optimize db layout due to performance we will touch message.
    In general we should have:
  • separate structure for the things module receive from untrusted sources (form the network or rpc, in general in transaction)
  • separate structure for the things which is validated and trusted and saved in module database
  • separate structure for the things in which module communicate with other modules i.e interfaces
  1. Some of the fields in BTCSpvProof are really not necessary (like confirming_btc_header as this can be taken from btc light client, or btc_transaction_index as this is part of submission key).

Solution to both problems is creating separate struct like message TransactionInfo which will hold all necessary transactions data necessary to prove its existence maybe like:

message TransactionInfo {
  bytes transaction
  bytes proof // maybe it could use here better format as we alrready processed and valideated the proof ? something to consider taking into account who an when will verify this proofs
  TransactionKey transactionKey // Although we already have it as part of SubmissionKey, maybe it is worth having it here to not relay on fact that TransactionInfo will be ordered in the same order as TransactionKeys in SubmissionKey
}

uint64 epoch = 3;
}

Expand Down
37 changes: 2 additions & 35 deletions proto/babylon/btccheckpoint/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";
package babylon.btccheckpoint.v1;

import "gogoproto/gogo.proto";
import "babylon/btccheckpoint/btccheckpoint.proto";

option go_package = "github.com/babylonchain/babylon/x/btccheckpoint/types";

Expand All @@ -11,43 +12,9 @@ service Msg {
returns (MsgInsertBTCSpvProofResponse);
}

// Consider we have a Merkle tree with following structure:
// ROOT
// / \
// H1234 H5555
// / \ \
// H12 H34 H55
// / \ / \ /
// H1 H2 H3 H4 H5
// L1 L2 L3 L4 L5
// To prove L3 was part of ROOT we need:
// - btc_transaction_index = 2 which in binary is 010
// (where 0 means going left, 1 means going right in the tree)
// - merkle_nodes we'd have H4 || H12 || H5555
// By looking at 010 we would know that H4 is a right sibling,
// H12 is left, H5555 is right again.
message BTCSpvProof {
// Valid bitcoin transaction containing OP_RETURN opcode.
bytes btc_transaction = 1;
// Index of transaction within the block. Index is needed to determine if
// currently hashed node is left or right.
uint32 btc_transaction_index = 2;
// List of concatenated intermediate merkle tree nodes, without root node and
// leaf node against which we calculate the proof. Each node has 32 byte
// length. Example proof can look like: 32_bytes_of_node1 || 32_bytes_of_node2
// || 32_bytes_of_node3 so the length of the proof will always be divisible
// by 32.
bytes merkle_nodes = 3;
// Valid btc header which confirms btc_transaction.
// Should have exactly 80 bytes
bytes confirming_btc_header = 4
[ (gogoproto.customtype) =
"github.com/babylonchain/babylon/types.BTCHeaderBytes" ];
}

message MsgInsertBTCSpvProof {
string submitter = 1;
repeated BTCSpvProof proofs = 2;
repeated babylon.btccheckpoint.v1.BTCSpvProof proofs = 2;
}

message MsgInsertBTCSpvProofResponse {}
2 changes: 1 addition & 1 deletion proto/babylon/zoneconcierge/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,5 @@ message QueryFinalizedChainInfoResponse {
// proof_epoch_sealed is the proof that the epoch is sealed
babylon.zoneconcierge.v1.ProofEpochSealed proof_epoch_sealed = 7;
// proof_epoch_submitted is the proof that the epoch's checkpoint is included in BTC ledger
babylon.btccheckpoint.v1.BTCSpvProof proof_epoch_submitted = 8;
repeated babylon.btccheckpoint.v1.BTCSpvProof proof_epoch_submitted = 8;
}
6 changes: 3 additions & 3 deletions x/btccheckpoint/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

var _ types.MsgServer = msgServer{}

type msgServer struct {
k Keeper
}
Expand Down Expand Up @@ -66,7 +68,7 @@ func (m msgServer) InsertBTCSpvProof(ctx context.Context, req *types.MsgInsertBT
sdkCtx,
epochNum,
submissionKey,
rawSubmission.GetSubmissionData(epochNum),
rawSubmission.GetSubmissionData(epochNum, req.Proofs),
rawCheckpointBytes,
)

Expand All @@ -76,5 +78,3 @@ func (m msgServer) InsertBTCSpvProof(ctx context.Context, req *types.MsgInsertBT

return &types.MsgInsertBTCSpvProofResponse{}, nil
}

var _ types.MsgServer = msgServer{}
Loading