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

Moving funds commitment implementation #3748

Merged
merged 55 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
6ff4af7
Added moving funds commitment implementation
tomaszslabon Nov 30, 2023
76ac573
Renamed variable
tomaszslabon Dec 1, 2023
8a078f2
Added check for nil wallet's main UTXO
tomaszslabon Dec 1, 2023
ae886cd
Used wallet public key hash as function's argument
tomaszslabon Dec 1, 2023
2d07451
Split condition check
tomaszslabon Dec 4, 2023
434f057
Added additional target wallet check
tomaszslabon Dec 4, 2023
377050e
Made log messages begin with lower case
tomaszslabon Dec 4, 2023
c35f245
Added description to balance check
tomaszslabon Dec 4, 2023
a0647a0
Merge branch 'main' into moving-funds-commitment
tomaszslabon Dec 5, 2023
c410f3c
Aligned unit tests
tomaszslabon Dec 5, 2023
51f268d
Improved calculation of target wallet count
tomaszslabon Dec 5, 2023
a918eeb
Refactored target wallets gathering
tomaszslabon Dec 5, 2023
b26befd
Added caching of operator IDs
tomaszslabon Dec 6, 2023
eb9a329
Integrated moving funds proposal into coordination mechanism
tomaszslabon Dec 7, 2023
f1c8275
Merge branch 'main' into moving-funds-commitment
tomaszslabon Dec 8, 2023
590e84d
Implemented move funds task
tomaszslabon Dec 11, 2023
d943730
Added moving funds message unmarshaling
tomaszslabon Jan 4, 2024
f8bdbef
Removed wallet public key hash from moving funds proposal
tomaszslabon Jan 4, 2024
6710e73
Added finding target wallets
tomaszslabon Jan 5, 2024
5fc3f77
Merge branch 'main' into moving-funds-commitment
tomaszslabon Jan 9, 2024
bec8275
Fixed linting errors
tomaszslabon Jan 9, 2024
f3250b3
Added submitting moved funds commitment
tomaszslabon Jan 9, 2024
70e0cd5
Added validation of moving funds proposal
tomaszslabon Jan 10, 2024
8ef8b58
Added fee estimation
tomaszslabon Jan 11, 2024
284eb37
Added functions docstrings
tomaszslabon Jan 15, 2024
44a59f5
Added unit tests for finding target wallets
tomaszslabon Jan 18, 2024
4ab2c94
Added unit tests for getting wallet member info
tomaszslabon Jan 19, 2024
d007443
Added commitment transaction confirmation check
tomaszslabon Jan 22, 2024
7067f73
Merge branch 'main' into moving-funds-commitment
tomaszslabon Jan 22, 2024
da7d745
Removed unnecessary functions
tomaszslabon Jan 22, 2024
0ee592c
Added unit tests for submitting moving funds commitment
tomaszslabon Jan 23, 2024
d847cd2
Updated chain interface
tomaszslabon Jan 23, 2024
c071c32
Added unit tests for estimating transaction fee
tomaszslabon Jan 24, 2024
ddbde93
Added unit tests for moving funds proposing
tomaszslabon Jan 24, 2024
38c2ab2
Minor refactor of unit tests
tomaszslabon Jan 25, 2024
a271da7
Merge branch 'main' into moving-funds-commitment
tomaszslabon Jan 26, 2024
d708675
Minor corrections
tomaszslabon Jan 26, 2024
1d5a723
Added additional logs
tomaszslabon Feb 2, 2024
6d5755f
Added check for wallet hash length during unmarshalling
tomaszslabon Feb 2, 2024
09dd59d
Renamed message
tomaszslabon Feb 2, 2024
e53fcd1
Removed package rename
tomaszslabon Feb 2, 2024
c7bb47e
Added function docstring
tomaszslabon Feb 2, 2024
5a4e2f2
Changed return value of function
tomaszslabon Feb 2, 2024
a013fa6
Simplified commitment look back blocks calculation
tomaszslabon Feb 5, 2024
d2b5cc0
Moved commitment hash calculation to the Tbtc chain
tomaszslabon Feb 5, 2024
7f16138
Renamed variable
tomaszslabon Feb 5, 2024
c41dc9e
Removed unnecessary check
tomaszslabon Feb 5, 2024
1d48758
Improved verification of commitment transaction confirmation
tomaszslabon Feb 6, 2024
ab27704
Added docstring for movingFundsProposalValidityBlocks
tomaszslabon Feb 6, 2024
136cf36
Updated TODO
tomaszslabon Feb 6, 2024
e4ec164
Moved creation of proposal after commitment submission
tomaszslabon Feb 7, 2024
fa17c41
Improved ceiling divide function
tomaszslabon Feb 7, 2024
e5d8ec3
Improved finding task-executing operator position on wallet member lists
tomaszslabon Feb 7, 2024
99aeec5
Added cache of operator address to wallet member IDs
tomaszslabon Feb 7, 2024
4672795
Refactored operator caching
tomaszslabon Feb 8, 2024
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
184 changes: 184 additions & 0 deletions pkg/chain/ethereum/tbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,25 @@ func computeMainUtxoHash(mainUtxo *bitcoin.UnspentTransactionOutput) [32]byte {
return mainUtxoHash
}

func (tc *TbtcChain) ComputeMovingFundsCommitmentHash(
targetWallets [][20]byte,
) [32]byte {
return computeMovingFundsCommitmentHash(targetWallets)
}

func computeMovingFundsCommitmentHash(targetWallets [][20]byte) [32]byte {
packedWallets := []byte{}

for _, wallet := range targetWallets {
packedWallets = append(packedWallets, wallet[:]...)
// Each wallet hash must be padded with 12 zero bytes following the
// actual hash.
packedWallets = append(packedWallets, make([]byte, 12)...)
lukasz-zimnoch marked this conversation as resolved.
Show resolved Hide resolved
}

return crypto.Keccak256Hash(packedWallets)
}

func (tc *TbtcChain) BuildDepositKey(
fundingTxHash bitcoin.Hash,
fundingOutputIndex uint32,
Expand Down Expand Up @@ -1463,6 +1482,81 @@ func (tc *TbtcChain) GetRedemptionParameters() (
return
}

func (tc *TbtcChain) GetWalletParameters() (
creationPeriod uint32,
creationMinBtcBalance uint64,
creationMaxBtcBalance uint64,
closureMinBtcBalance uint64,
maxAge uint32,
maxBtcTransfer uint64,
closingPeriod uint32,
err error,
) {
parameters, callErr := tc.bridge.WalletParameters()
if callErr != nil {
err = callErr
return
}

creationPeriod = parameters.WalletCreationPeriod
creationMinBtcBalance = parameters.WalletCreationMinBtcBalance
creationMaxBtcBalance = parameters.WalletCreationMaxBtcBalance
closureMinBtcBalance = parameters.WalletClosureMinBtcBalance
maxAge = parameters.WalletMaxAge
maxBtcTransfer = parameters.WalletMaxBtcTransfer
closingPeriod = parameters.WalletClosingPeriod

return
}

func (tc *TbtcChain) GetLiveWalletsCount() (uint32, error) {
return tc.bridge.LiveWalletsCount()
}

func (tc *TbtcChain) PastMovingFundsCommitmentSubmittedEvents(
filter *tbtc.MovingFundsCommitmentSubmittedEventFilter,
) ([]*tbtc.MovingFundsCommitmentSubmittedEvent, error) {
var startBlock uint64
var endBlock *uint64
var walletPublicKeyHash [][20]byte

if filter != nil {
startBlock = filter.StartBlock
endBlock = filter.EndBlock
walletPublicKeyHash = filter.WalletPublicKeyHash
}

events, err := tc.bridge.PastMovingFundsCommitmentSubmittedEvents(
startBlock,
endBlock,
walletPublicKeyHash,
)
if err != nil {
return nil, err
}

convertedEvents := make([]*tbtc.MovingFundsCommitmentSubmittedEvent, 0)
for _, event := range events {
convertedEvent := &tbtc.MovingFundsCommitmentSubmittedEvent{
WalletPublicKeyHash: event.WalletPubKeyHash,
TargetWallets: event.TargetWallets,
Submitter: chain.Address(event.Submitter.Hex()),
BlockNumber: event.Raw.BlockNumber,
}

convertedEvents = append(convertedEvents, convertedEvent)
}

sort.SliceStable(
convertedEvents,
func(i, j int) bool {
return convertedEvents[i].BlockNumber < convertedEvents[j].BlockNumber
},
)

return convertedEvents, err
}

func buildDepositKey(
fundingTxHash bitcoin.Hash,
fundingOutputIndex uint32,
Expand Down Expand Up @@ -1571,6 +1665,28 @@ func (tc *TbtcChain) GetDepositSweepMaxSize() (uint16, error) {
return tc.walletProposalValidator.DEPOSITSWEEPMAXSIZE()
}

func (tc *TbtcChain) SubmitMovingFundsCommitment(
walletPublicKeyHash [20]byte,
walletMainUTXO bitcoin.UnspentTransactionOutput,
walletMembersIDs []uint32,
walletMemberIndex uint32,
targetWallets [][20]byte,
) error {
mainUtxo := tbtcabi.BitcoinTxUTXO{
TxHash: walletMainUTXO.Outpoint.TransactionHash,
TxOutputIndex: walletMainUTXO.Outpoint.OutputIndex,
TxOutputValue: uint64(walletMainUTXO.Value),
}
_, err := tc.bridge.SubmitMovingFundsCommitment(
walletPublicKeyHash,
mainUtxo,
walletMembersIDs,
big.NewInt(int64(walletMemberIndex)),
targetWallets,
)
return err
}

func (tc *TbtcChain) ValidateRedemptionProposal(
walletPublicKeyHash [20]byte,
proposal *tbtc.RedemptionProposal,
Expand Down Expand Up @@ -1660,3 +1776,71 @@ func (tc *TbtcChain) ValidateHeartbeatProposal(

return nil
}

func (tc *TbtcChain) GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
) {
parameters, callErr := tc.bridge.MovingFundsParameters()
if callErr != nil {
err = callErr
return
}

txMaxTotalFee = parameters.MovingFundsTxMaxTotalFee
dustThreshold = parameters.MovingFundsDustThreshold
timeoutResetDelay = parameters.MovingFundsTimeoutResetDelay
timeout = parameters.MovingFundsTimeout
timeoutSlashingAmount = parameters.MovingFundsTimeoutSlashingAmount
timeoutNotifierRewardMultiplier = parameters.MovingFundsTimeoutNotifierRewardMultiplier
commitmentGasOffset = parameters.MovingFundsCommitmentGasOffset
sweepTxMaxTotalFee = parameters.MovedFundsSweepTxMaxTotalFee
sweepTimeout = parameters.MovedFundsSweepTimeout
sweepTimeoutSlashingAmount = parameters.MovedFundsSweepTimeoutSlashingAmount
sweepTimeoutNotifierRewardMultiplier = parameters.MovedFundsSweepTimeoutNotifierRewardMultiplier

return
}

func (tc *TbtcChain) ValidateMovingFundsProposal(
walletPublicKeyHash [20]byte,
mainUTXO *bitcoin.UnspentTransactionOutput,
proposal *tbtc.MovingFundsProposal,
) error {
abiProposal := tbtcabi.WalletProposalValidatorMovingFundsProposal{
WalletPubKeyHash: walletPublicKeyHash,
TargetWallets: proposal.TargetWallets,
MovingFundsTxFee: proposal.MovingFundsTxFee,
}
abiMainUTXO := tbtcabi.BitcoinTxUTXO3{
TxHash: mainUTXO.Outpoint.TransactionHash,
TxOutputIndex: mainUTXO.Outpoint.OutputIndex,
TxOutputValue: uint64(mainUTXO.Value),
}

valid, err := tc.walletProposalValidator.ValidateMovingFundsProposal(
abiProposal,
abiMainUTXO,
)
if err != nil {
return fmt.Errorf("validation failed: [%v]", err)
}

// Should never happen because `validateMovingFundsProposal` returns true
// or reverts (returns an error) but do the check just in case.
if !valid {
return fmt.Errorf("unexpected validation result")
}

return nil
}
39 changes: 39 additions & 0 deletions pkg/chain/ethereum/tbtc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,45 @@ func TestComputeMainUtxoHash(t *testing.T) {
testutils.AssertBytesEqual(t, expectedMainUtxoHash, mainUtxoHash[:])
}

func TestComputeMovingFundsCommitmentHash(t *testing.T) {
toByte20 := func(s string) [20]byte {
bytes, err := hex.DecodeString(s)
if err != nil {
t.Fatal(err)
}

if len(bytes) != 20 {
t.Fatal("incorrect hexstring length")
}

var result [20]byte
copy(result[:], bytes[:])
return result
}

targetWallets := [][20]byte{
toByte20("4b440cb29c80c3f256212d8fdd4f2125366f3c91"),
toByte20("888f01315e0268bfa05d5e522f8d63f6824d9a96"),
toByte20("b2a89e53a4227dbe530a52a1c419040735fa636c"),
}

movingFundsCommitmentHash := computeMovingFundsCommitmentHash(
targetWallets,
)

expectedMovingFundsCommitmentHash, err := hex.DecodeString(
"8ba62d1d754a3429e2ff1fb4f523b5fad2b605c873a2968bb5985a625eb96202",
)
if err != nil {
t.Fatal(err)
}
testutils.AssertBytesEqual(
t,
expectedMovingFundsCommitmentHash,
movingFundsCommitmentHash[:],
)
}

// Test data based on: https://etherscan.io/tx/0x97c7a293127a604da77f7ef8daf4b19da2bf04327dd891b6d717eaef89bd8bca
func TestBuildDepositKey(t *testing.T) {
fundingTxHash, err := bitcoin.NewHashFromString(
Expand Down
24 changes: 24 additions & 0 deletions pkg/tbtc/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,15 @@ type WalletProposalValidatorChain interface {
walletPublicKeyHash [20]byte,
proposal *HeartbeatProposal,
) error

// ValidateMovingFundsProposal validates the given moving funds proposal
// against the chain. Returns an error if the proposal is not valid or
// nil otherwise.
ValidateMovingFundsProposal(
walletPublicKeyHash [20]byte,
mainUTXO *bitcoin.UnspentTransactionOutput,
proposal *MovingFundsProposal,
) error
}

// RedemptionRequestedEvent represents a redemption requested event.
Expand All @@ -376,6 +385,21 @@ type RedemptionRequestedEventFilter struct {
Redeemer []chain.Address
}

// MovingFundsCommitmentSubmittedEvent represents a moving funds commitment submitted event.
type MovingFundsCommitmentSubmittedEvent struct {
WalletPublicKeyHash [20]byte
TargetWallets [][20]byte
Submitter chain.Address
BlockNumber uint64
}

// MovingFundsCommitmentSubmittedEventFilter is a component allowing to filter MovingFundsCommitmentSubmittedEvent.
type MovingFundsCommitmentSubmittedEventFilter struct {
StartBlock uint64
EndBlock *uint64
WalletPublicKeyHash [][20]byte
}

// Chain represents the interface that the TBTC module expects to interact
// with the anchoring blockchain on.
type Chain interface {
Expand Down
21 changes: 21 additions & 0 deletions pkg/tbtc/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,19 @@ func (lc *localChain) operatorAddress() (chain.Address, error) {
return lc.Signing().PublicKeyToAddress(operatorPublicKey)
}

func (lc *localChain) GetWalletParameters() (
creationPeriod uint32,
creationMinBtcBalance uint64,
creationMaxBtcBalance uint64,
closureMinBtcBalance uint64,
maxAge uint32,
maxBtcTransfer uint64,
closingPeriod uint32,
err error,
) {
panic("unsupported")
}

func (lc *localChain) ValidateDepositSweepProposal(
walletPublicKeyHash [20]byte,
proposal *DepositSweepProposal,
Expand Down Expand Up @@ -891,6 +904,14 @@ func (lc *localChain) setHeartbeatProposalValidationResult(
lc.heartbeatProposalValidations[proposal.Message] = result
}

func (lc *localChain) ValidateMovingFundsProposal(
walletPublicKeyHash [20]byte,
mainUTXO *bitcoin.UnspentTransactionOutput,
proposal *MovingFundsProposal,
) error {
panic("unsupported")
}

// Connect sets up the local chain.
func Connect(blockTime ...time.Duration) *localChain {
operatorPrivateKey, _, err := operator.GenerateKeyPair(local_v1.DefaultCurve)
Expand Down
2 changes: 2 additions & 0 deletions pkg/tbtc/coordination.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func (cf *coordinationFault) String() string {
type CoordinationProposalRequest struct {
WalletPublicKeyHash [20]byte
WalletOperators []chain.Address
ExecutingOperator chain.Address
ActionsChecklist []WalletActionType
}

Expand Down Expand Up @@ -581,6 +582,7 @@ func (ce *coordinationExecutor) executeLeaderRoutine(
&CoordinationProposalRequest{
WalletPublicKeyHash: walletPublicKeyHash,
WalletOperators: ce.coordinatedWallet.signingGroupOperators,
ExecutingOperator: ce.operatorAddress,
ActionsChecklist: actionsChecklist,
},
)
Expand Down
Loading
Loading