Skip to content

Commit

Permalink
Adjust SPV maintainer to recent changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-zimnoch committed Dec 6, 2023
1 parent d34b9e8 commit 19bc96b
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 122 deletions.
3 changes: 1 addition & 2 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,7 @@ func initMaintainerFlags(command *cobra.Command, cfg *config.Config) {
&cfg.Maintainer.Spv.HistoryDepth,
"spv.historyDepth",
spv.DefaultHistoryDepth,
"Number of blocks to look back for past deposit sweep proposal "+
"submitted events.",
"Number of blocks to look back for past wallet-related events.",
)

command.Flags().IntVar(
Expand Down
16 changes: 16 additions & 0 deletions pkg/maintainer/spv/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,20 @@ type Chain interface {
mainUTXO bitcoin.UnspentTransactionOutput,
walletPublicKeyHash [20]byte,
) error

// PastDepositRevealedEvents fetches past deposit reveal events according
// to the provided filter or unfiltered if the filter is nil. Returned
// events are sorted by the block number in the ascending order, i.e. the
// latest event is at the end of the slice.
PastDepositRevealedEvents(
filter *tbtc.DepositRevealedEventFilter,
) ([]*tbtc.DepositRevealedEvent, error)

// PastRedemptionRequestedEvents fetches past redemption requested events according
// to the provided filter or unfiltered if the filter is nil. Returned
// events are sorted by the block number in the ascending order, i.e. the
// latest event is at the end of the slice.
PastRedemptionRequestedEvents(
filter *tbtc.RedemptionRequestedEventFilter,
) ([]*tbtc.RedemptionRequestedEvent, error)
}
175 changes: 164 additions & 11 deletions pkg/maintainer/spv/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"fmt"
"math/big"
"sync"
Expand Down Expand Up @@ -32,12 +33,14 @@ type submittedDepositSweepProof struct {
type localChain struct {
mutex sync.Mutex

blockCounter chain.BlockCounter
wallets map[[20]byte]*tbtc.WalletChainData
depositRequests map[[32]byte]*tbtc.DepositChainRequest
pendingRedemptionRequests map[[32]byte]*tbtc.RedemptionRequest
submittedRedemptionProofs []*submittedRedemptionProof
submittedDepositSweepProofs []*submittedDepositSweepProof
blockCounter chain.BlockCounter
wallets map[[20]byte]*tbtc.WalletChainData
depositRequests map[[32]byte]*tbtc.DepositChainRequest
pendingRedemptionRequests map[[32]byte]*tbtc.RedemptionRequest
submittedRedemptionProofs []*submittedRedemptionProof
submittedDepositSweepProofs []*submittedDepositSweepProof
pastRedemptionRequestedEvents map[[32]byte][]*tbtc.RedemptionRequestedEvent
pastDepositRevealedEvents map[[32]byte][]*tbtc.DepositRevealedEvent

txProofDifficultyFactor *big.Int
currentEpoch uint64
Expand All @@ -47,11 +50,13 @@ type localChain struct {

func newLocalChain() *localChain {
return &localChain{
wallets: make(map[[20]byte]*tbtc.WalletChainData),
depositRequests: make(map[[32]byte]*tbtc.DepositChainRequest),
pendingRedemptionRequests: make(map[[32]byte]*tbtc.RedemptionRequest),
submittedRedemptionProofs: make([]*submittedRedemptionProof, 0),
submittedDepositSweepProofs: make([]*submittedDepositSweepProof, 0),
wallets: make(map[[20]byte]*tbtc.WalletChainData),
depositRequests: make(map[[32]byte]*tbtc.DepositChainRequest),
pendingRedemptionRequests: make(map[[32]byte]*tbtc.RedemptionRequest),
submittedRedemptionProofs: make([]*submittedRedemptionProof, 0),
submittedDepositSweepProofs: make([]*submittedDepositSweepProof, 0),
pastRedemptionRequestedEvents: make(map[[32]byte][]*tbtc.RedemptionRequestedEvent),
pastDepositRevealedEvents: make(map[[32]byte][]*tbtc.DepositRevealedEvent),
}
}

Expand Down Expand Up @@ -338,6 +343,154 @@ func (lc *localChain) setCurrentAndPrevEpochDifficulty(
lc.previousEpochDifficulty = previousEpochDifficulty
}

func (lc *localChain) PastDepositRevealedEvents(
filter *tbtc.DepositRevealedEventFilter,
) ([]*tbtc.DepositRevealedEvent, error) {
lc.mutex.Lock()
defer lc.mutex.Unlock()

eventsKey, err := buildPastDepositRevealedEventsKey(filter)
if err != nil {
return nil, err
}

events, ok := lc.pastDepositRevealedEvents[eventsKey]
if !ok {
return nil, fmt.Errorf("no events for given filter")
}

return events, nil
}

func (lc *localChain) addPastDepositRevealedEvent(
filter *tbtc.DepositRevealedEventFilter,
event *tbtc.DepositRevealedEvent,
) error {
lc.mutex.Lock()
defer lc.mutex.Unlock()

eventsKey, err := buildPastDepositRevealedEventsKey(filter)
if err != nil {
return err
}

lc.pastDepositRevealedEvents[eventsKey] = append(
lc.pastDepositRevealedEvents[eventsKey],
event,
)

return nil
}

func buildPastDepositRevealedEventsKey(
filter *tbtc.DepositRevealedEventFilter,
) ([32]byte, error) {
if filter == nil {
return [32]byte{}, nil
}

var buffer bytes.Buffer

startBlock := make([]byte, 8)
binary.BigEndian.PutUint64(startBlock, filter.StartBlock)
buffer.Write(startBlock)

if filter.EndBlock != nil {
endBlock := make([]byte, 8)
binary.BigEndian.PutUint64(startBlock, *filter.EndBlock)
buffer.Write(endBlock)
}

for _, depositor := range filter.Depositor {
depositorBytes, err := hex.DecodeString(depositor.String())
if err != nil {
return [32]byte{}, err
}

buffer.Write(depositorBytes)
}

for _, walletPublicKeyHash := range filter.WalletPublicKeyHash {
buffer.Write(walletPublicKeyHash[:])
}

return sha256.Sum256(buffer.Bytes()), nil
}

func (lc *localChain) PastRedemptionRequestedEvents(
filter *tbtc.RedemptionRequestedEventFilter,
) ([]*tbtc.RedemptionRequestedEvent, error) {
lc.mutex.Lock()
defer lc.mutex.Unlock()

eventsKey, err := buildPastRedemptionRequestedEventsKey(filter)
if err != nil {
return nil, err
}

events, ok := lc.pastRedemptionRequestedEvents[eventsKey]
if !ok {
return nil, fmt.Errorf("no events for given filter")
}

return events, nil
}

func (lc *localChain) addPastRedemptionRequestedEvent(
filter *tbtc.RedemptionRequestedEventFilter,
event *tbtc.RedemptionRequestedEvent,
) error {
lc.mutex.Lock()
defer lc.mutex.Unlock()

eventsKey, err := buildPastRedemptionRequestedEventsKey(filter)
if err != nil {
return err
}

lc.pastRedemptionRequestedEvents[eventsKey] = append(
lc.pastRedemptionRequestedEvents[eventsKey],
event,
)

return nil
}

func buildPastRedemptionRequestedEventsKey(
filter *tbtc.RedemptionRequestedEventFilter,
) ([32]byte, error) {
if filter == nil {
return [32]byte{}, nil
}

var buffer bytes.Buffer

startBlock := make([]byte, 8)
binary.BigEndian.PutUint64(startBlock, filter.StartBlock)
buffer.Write(startBlock)

if filter.EndBlock != nil {
endBlock := make([]byte, 8)
binary.BigEndian.PutUint64(startBlock, *filter.EndBlock)
buffer.Write(endBlock)
}

for _, walletPublicKeyHash := range filter.WalletPublicKeyHash {
buffer.Write(walletPublicKeyHash[:])
}

for _, redeemer := range filter.Redeemer {
redeemerHex, err := hex.DecodeString(redeemer.String())
if err != nil {
return [32]byte{}, err
}

buffer.Write(redeemerHex)
}

return sha256.Sum256(buffer.Bytes()), nil
}

type mockBlockCounter struct {
mutex sync.Mutex
currentBlock uint64
Expand Down
24 changes: 11 additions & 13 deletions pkg/maintainer/spv/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
const (
// DefaultHistoryDepth is the default value for history depth which is the
// number of blocks to look back from the current block when searching for
// past proposal submission events. The value is the approximate number of
// past wallet-related events. The value is the approximate number of
// Ethereum blocks in a week, assuming one block is 12s.
DefaultHistoryDepth = 50400

Expand Down Expand Up @@ -35,22 +35,20 @@ type Config struct {
Enabled bool

// HistoryDepth is the number of blocks to look back from the current block
// when searching for past proposal submission events.
// To find Bitcoin transactions for which the SPV proof should be submitted,
// the maintainer first inspects the proposal events from the wallet
// coordinator contract. This depth determines how far into the past the
// system will consider events for processing. This value must not be too
// high so that the event lookup is efficient. At the same time, this value
// can not be too low to make sure all performed and not yet proven
// transactions can be found.
// when searching for past wallet-related events. To find Bitcoin transactions
// for which the SPV proof should be submitted, the maintainer first inspects
// the appropriate type of wallet-related events. This depth determines how
// far into the past the system will consider events for processing. This
// value must not be too high so that the event lookup is efficient. At the
// same time, this value can not be too low to make sure all performed and
// not yet proven transactions can be found.
HistoryDepth uint64

// TransactionLimit sets the maximum number of confirmed transactions
// returned when getting transactions for a public key hash. Once the
// maintainer establishes the list of proposals of given type, based on the
// proposal submission events from the wallet coordinator contract, it needs
// to check Bitcoin transactions executed by the wallet. Then, it tries to
// find the transactions matching the given proposal type. For example, if set
// maintainer establishes the list of wallets, it needs to check Bitcoin
// transactions executed by each wallet. Then, it tries to find the
// transactions matching the given proposal type. For example, if set
// to `20`, only the latest twenty transactions will be returned. This
// value must not be too high so that the transaction lookup is efficient.
// At the same time, this value can not be too low to make sure the
Expand Down
10 changes: 5 additions & 5 deletions pkg/maintainer/spv/deposit_sweep.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,23 +245,23 @@ func getUnprovenDepositSweepTransactions(
// searched for.
startBlock := currentBlock - historyDepth

depositSweepProposals, err :=
spvChain.PastDepositSweepProposalSubmittedEvents(
&tbtc.DepositSweepProposalSubmittedEventFilter{
events, err :=
spvChain.PastDepositRevealedEvents(
&tbtc.DepositRevealedEventFilter{
StartBlock: startBlock,
},
)
if err != nil {
return nil, fmt.Errorf(
"failed to get past deposit sweep proposal submitted events: [%v]",
"failed to get past deposit revealed events: [%v]",
err,
)
}

// There will often be multiple events emitted for a single wallet. Prepare
// a list of unique wallet public key hashes.
walletPublicKeyHashes := uniqueWalletPublicKeyHashes(
depositSweepProposals,
events,
)

unprovenDepositSweepTransactions := []*bitcoin.Transaction{}
Expand Down
40 changes: 16 additions & 24 deletions pkg/maintainer/spv/deposit_sweep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,43 +313,35 @@ func TestGetUnprovenDepositSweepTransactions(t *testing.T) {
},
)

// Add proposal events for the wallets. Only wallet public key hash field
// Add deposit events for the wallets. Only wallet public key hash field
// is relevant as those events are just used to get a list of distinct
// wallets who performed deposit sweeps recently. The block number field
// is just to make them distinguishable while reading.
proposalEvents := []*tbtc.DepositSweepProposalSubmittedEvent{
// wallets who likely performed deposit sweeps recently. The block number
// field is just to make them distinguishable while reading.
events := []*tbtc.DepositRevealedEvent{
{
Proposal: &tbtc.DepositSweepProposal{
WalletPublicKeyHash: wallets[0].walletPublicKeyHash,
},
BlockNumber: 100,
WalletPublicKeyHash: wallets[0].walletPublicKeyHash,
BlockNumber: 100,
},
{
Proposal: &tbtc.DepositSweepProposal{
WalletPublicKeyHash: wallets[0].walletPublicKeyHash,
},
BlockNumber: 200,
WalletPublicKeyHash: wallets[0].walletPublicKeyHash,
BlockNumber: 200,
},
{
Proposal: &tbtc.DepositSweepProposal{
WalletPublicKeyHash: wallets[1].walletPublicKeyHash,
},
BlockNumber: 300,
WalletPublicKeyHash: wallets[1].walletPublicKeyHash,
BlockNumber: 300,
},
{
Proposal: &tbtc.DepositSweepProposal{
WalletPublicKeyHash: wallets[1].walletPublicKeyHash,
},
BlockNumber: 400,
WalletPublicKeyHash: wallets[1].walletPublicKeyHash,
BlockNumber: 400,
},
}

for _, proposalEvent := range proposalEvents {
err := spvChain.AddPastDepositSweepProposalSubmittedEvent(
&tbtc.DepositSweepProposalSubmittedEventFilter{
for _, event := range events {
err := spvChain.addPastDepositRevealedEvent(
&tbtc.DepositRevealedEventFilter{
StartBlock: currentBlock - historyDepth,
},
proposalEvent,
event,
)
if err != nil {
t.Fatal(err)
Expand Down
10 changes: 5 additions & 5 deletions pkg/maintainer/spv/redemptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,23 +146,23 @@ func getUnprovenRedemptionTransactions(
// searched for.
startBlock := currentBlock - historyDepth

redemptionProposals, err :=
spvChain.PastRedemptionProposalSubmittedEvents(
&tbtc.RedemptionProposalSubmittedEventFilter{
events, err :=
spvChain.PastRedemptionRequestedEvents(
&tbtc.RedemptionRequestedEventFilter{
StartBlock: startBlock,
},
)
if err != nil {
return nil, fmt.Errorf(
"failed to get past redemption proposal submitted events: [%v]",
"failed to get past redemption requested events: [%v]",
err,
)
}

// There will often be multiple events emitted for a single wallet. Prepare
// a list of unique wallet public key hashes.
walletPublicKeyHashes := uniqueWalletPublicKeyHashes(
redemptionProposals,
events,
)

var unprovenRedemptionTransactions []*bitcoin.Transaction
Expand Down
Loading

0 comments on commit 19bc96b

Please sign in to comment.