Skip to content

Commit

Permalink
Added unit tests for inactivity executor
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaszslabon committed May 13, 2024
1 parent 7137d4f commit 8b92d0e
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 5 deletions.
74 changes: 69 additions & 5 deletions pkg/tbtc/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type localChain struct {
dkgResultChallengeHandlersMutex sync.Mutex
dkgResultChallengeHandlers map[int]func(submission *DKGResultChallengedEvent)

inactivityClaimedHandlersMutex sync.Mutex
inactivityClaimedHandlers map[int]func(submission *InactivityClaimedEvent)

dkgMutex sync.Mutex
dkgState DKGState
dkgResult *DKGChainResult
Expand All @@ -49,6 +52,9 @@ type localChain struct {
walletsMutex sync.Mutex
wallets map[[20]byte]*WalletChainData

inactivityNonceMutex sync.Mutex
inactivityNonces map[[32]byte]uint64

blocksByTimestampMutex sync.Mutex
blocksByTimestamp map[uint64]uint64

Expand Down Expand Up @@ -553,9 +559,20 @@ func (lc *localChain) DKGParameters() (*DKGParameters, error) {
}

func (lc *localChain) OnInactivityClaimed(
func(event *InactivityClaimedEvent),
handler func(event *InactivityClaimedEvent),
) subscription.EventSubscription {
panic("unsupported")
lc.inactivityClaimedHandlersMutex.Lock()
defer lc.inactivityClaimedHandlersMutex.Unlock()

handlerID := generateHandlerID()
lc.inactivityClaimedHandlers[handlerID] = handler

return subscription.NewEventSubscription(func() {
lc.inactivityClaimedHandlersMutex.Lock()
defer lc.inactivityClaimedHandlersMutex.Unlock()

delete(lc.inactivityClaimedHandlers, handlerID)
})
}

func (lc *localChain) AssembleInactivityClaim(
Expand All @@ -567,15 +584,54 @@ func (lc *localChain) AssembleInactivityClaim(
*InactivityClaim,
error,
) {
panic("unsupported")
signingMembersIndexes := make([]group.MemberIndex, 0)
signaturesConcatenation := make([]byte, 0)
for memberIndex, signature := range signatures {
signingMembersIndexes = append(signingMembersIndexes, memberIndex)
signaturesConcatenation = append(signaturesConcatenation, signature...)
}

return &InactivityClaim{
WalletID: walletID,
InactiveMembersIndices: inactiveMembersIndices,
HeartbeatFailed: heartbeatFailed,
Signatures: signaturesConcatenation,
SigningMembersIndices: signingMembersIndexes,
}, nil
}

func (lc *localChain) SubmitInactivityClaim(
claim *InactivityClaim,
nonce *big.Int,
groupMembers []uint32,
) error {
panic("unsupported")
lc.inactivityClaimedHandlersMutex.Lock()
defer lc.inactivityClaimedHandlersMutex.Unlock()

lc.inactivityNonceMutex.Lock()
defer lc.inactivityNonceMutex.Unlock()

if nonce.Uint64() != lc.inactivityNonces[claim.WalletID] {
return fmt.Errorf("wrong inactivity claim nonce")
}

blockNumber, err := lc.blockCounter.CurrentBlock()
if err != nil {
return fmt.Errorf("failed to get the current block")
}

for _, handler := range lc.inactivityClaimedHandlers {
handler(&InactivityClaimedEvent{
WalletID: claim.WalletID,
Nonce: nonce,
Notifier: "",
BlockNumber: blockNumber,
})
}

lc.inactivityNonces[claim.WalletID]++

return nil
}

func (lc *localChain) CalculateInactivityClaimHash(
Expand All @@ -598,7 +654,11 @@ func (lc *localChain) CalculateInactivityClaimHash(
}

func (lc *localChain) GetInactivityClaimNonce(walletID [32]byte) (*big.Int, error) {
panic("unsupported")
lc.inactivityNonceMutex.Lock()
defer lc.inactivityNonceMutex.Unlock()

nonce := lc.inactivityNonces[walletID]
return big.NewInt(int64(nonce)), nil
}

func (lc *localChain) PastDepositRevealedEvents(
Expand Down Expand Up @@ -1182,7 +1242,11 @@ func ConnectWithKey(
dkgResultChallengeHandlers: make(
map[int]func(submission *DKGResultChallengedEvent),
),
inactivityClaimedHandlers: make(
map[int]func(submission *InactivityClaimedEvent),
),
wallets: make(map[[20]byte]*WalletChainData),
inactivityNonces: make(map[[32]byte]uint64),
blocksByTimestamp: make(map[uint64]uint64),
blocksHashesByNumber: make(map[uint64][32]byte),
pastDepositRevealedEvents: make(map[[32]byte][]*DepositRevealedEvent),
Expand Down
180 changes: 180 additions & 0 deletions pkg/tbtc/inactivity_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,199 @@
package tbtc

import (
"context"
"fmt"
"math/big"
"reflect"
"testing"
"time"

"golang.org/x/crypto/sha3"

"github.com/keep-network/keep-core/internal/testutils"
"github.com/keep-network/keep-core/pkg/bitcoin"
"github.com/keep-network/keep-core/pkg/chain"
"github.com/keep-network/keep-core/pkg/chain/local_v1"
"github.com/keep-network/keep-core/pkg/generator"
"github.com/keep-network/keep-core/pkg/internal/tecdsatest"
"github.com/keep-network/keep-core/pkg/net/local"
"github.com/keep-network/keep-core/pkg/operator"
"github.com/keep-network/keep-core/pkg/protocol/group"
"github.com/keep-network/keep-core/pkg/protocol/inactivity"
"github.com/keep-network/keep-core/pkg/tecdsa"
)

func TestInactivityClaimExecutor_ClaimInactivity(t *testing.T) {
executor, walletEcdsaID, chain := setupInactivityClaimExecutorScenario(t)

initialNonce, err := chain.GetInactivityClaimNonce(walletEcdsaID)
if err != nil {
t.Fatal(err)
}

ctx, cancelCtx := context.WithCancel(context.Background())
defer cancelCtx()

message := big.NewInt(100)
inactiveMembersIndexes := []group.MemberIndex{1, 4}

err = executor.claimInactivity(
ctx,
inactiveMembersIndexes,
true,
message,
)
if err != nil {
t.Fatal(err)
}

currentNonce, err := chain.GetInactivityClaimNonce(walletEcdsaID)
if err != nil {
t.Fatal(err)
}

expectedNonceDiff := uint64(1)
nonceDiff := currentNonce.Uint64() - initialNonce.Uint64()

testutils.AssertUintsEqual(
t,
"inactivity nonce difference",
expectedNonceDiff,
nonceDiff,
)
}

func TestInactivityClaimExecutor_ClaimInactivity_Busy(t *testing.T) {
executor, _, _ := setupInactivityClaimExecutorScenario(t)

ctx, cancelCtx := context.WithCancel(context.Background())
defer cancelCtx()

message := big.NewInt(100)
inactiveMembersIndexes := []group.MemberIndex{1, 4}

errChan := make(chan error, 1)
go func() {
err := executor.claimInactivity(
ctx,
inactiveMembersIndexes,
true,
message,
)
errChan <- err
}()

time.Sleep(100 * time.Millisecond)

err := executor.claimInactivity(
ctx,
inactiveMembersIndexes,
true,
message,
)
testutils.AssertErrorsSame(t, errInactivityClaimExecutorBusy, err)

err = <-errChan
if err != nil {
t.Errorf("unexpected error: [%v]", err)
}
}

func setupInactivityClaimExecutorScenario(t *testing.T) (
*inactivityClaimExecutor,
[32]byte,
*localChain,
) {
groupParameters := &GroupParameters{
GroupSize: 5,
GroupQuorum: 4,
HonestThreshold: 3,
}

operatorPrivateKey, operatorPublicKey, err := operator.GenerateKeyPair(
local_v1.DefaultCurve,
)
if err != nil {
t.Fatal(err)
}

localChain := ConnectWithKey(operatorPrivateKey)

localProvider := local.ConnectWithKey(operatorPublicKey)

operatorAddress, err := localChain.Signing().PublicKeyToAddress(
operatorPublicKey,
)
if err != nil {
t.Fatal(err)
}

var operators []chain.Address
for i := 0; i < groupParameters.GroupSize; i++ {
operators = append(operators, operatorAddress)
}

testData, err := tecdsatest.LoadPrivateKeyShareTestFixtures(
groupParameters.GroupSize,
)
if err != nil {
t.Fatalf("failed to load test data: [%v]", err)
}

signers := make([]*signer, len(testData))
for i := range testData {
privateKeyShare := tecdsa.NewPrivateKeyShare(testData[i])

signers[i] = &signer{
wallet: wallet{
publicKey: privateKeyShare.PublicKey(),
signingGroupOperators: operators,
},
signingGroupMemberIndex: group.MemberIndex(i + 1),
privateKeyShare: privateKeyShare,
}
}

keyStorePersistence := createMockKeyStorePersistence(t, signers...)

walletPublicKeyHash := bitcoin.PublicKeyHash(signers[0].wallet.publicKey)
ecdsaWalletID := [32]byte{1, 2, 3}

localChain.setWallet(
walletPublicKeyHash,
&WalletChainData{
EcdsaWalletID: ecdsaWalletID,
},
)

node, err := newNode(
groupParameters,
localChain,
newLocalBitcoinChain(),
localProvider,
keyStorePersistence,
&mockPersistenceHandle{},
generator.StartScheduler(),
&mockCoordinationProposalGenerator{},
Config{},
)
if err != nil {
t.Fatal(err)
}

executor, ok, err := node.getInactivityClaimExecutor(
signers[0].wallet.publicKey,
)
if err != nil {
t.Fatal(err)
}
if !ok {
t.Fatal("node is supposed to control wallet signers")
}

return executor, ecdsaWalletID, localChain
}

func TestSignClaim_SigningSuccessful(t *testing.T) {
chain := Connect()
inactivityClaimSigner := newInactivityClaimSigner(chain)
Expand Down

0 comments on commit 8b92d0e

Please sign in to comment.