Skip to content

Commit

Permalink
Handled publishing jobs for signers
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaszslabon committed Apr 23, 2024
1 parent d6e9219 commit 147d82d
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 42 deletions.
12 changes: 8 additions & 4 deletions pkg/chain/ethereum/tbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,15 +995,19 @@ func (tc *TbtcChain) DKGParameters() (*tbtc.DKGParameters, error) {
}

func (tc *TbtcChain) CalculateInactivityClaimSignatureHash(
nonce *big.Int,
walletPublicKey *ecdsa.PublicKey,
inactiveMembersIndexes []group.MemberIndex,
heartbeatFailed bool,
claim *inactivity.Claim,
) (inactivity.ClaimSignatureHash, error) {
// TODO: Implement
return inactivity.ClaimSignatureHash{}, nil
}

func (tc *TbtcChain) GetInactivityClaimNonce(
walletID [32]byte,
) (*big.Int, error) {
// TODO: Implement
return nil, nil
}

func (tc *TbtcChain) PastDepositRevealedEvents(
filter *tbtc.DepositRevealedEventFilter,
) ([]*tbtc.DepositRevealedEvent, error) {
Expand Down
20 changes: 13 additions & 7 deletions pkg/tbtc/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,6 @@ type DistributedKeyGenerationChain interface {
startBlock uint64,
) (dkg.ResultSignatureHash, error)

CalculateInactivityClaimSignatureHash(
nonce *big.Int,
walletPublicKey *ecdsa.PublicKey,
inactiveMembersIndexes []group.MemberIndex,
heartbeatFailed bool,
) (inactivity.ClaimSignatureHash, error)

// IsDKGResultValid checks whether the submitted DKG result is valid from
// the on-chain contract standpoint.
IsDKGResultValid(dkgResult *DKGChainResult) (bool, error)
Expand All @@ -128,6 +121,18 @@ type DistributedKeyGenerationChain interface {
DKGParameters() (*DKGParameters, error)
}

type InactivityClaimChain interface {
// CalculateInactivityClaimSignatureHash calculates hash for the given
// inactivity claim.
CalculateInactivityClaimSignatureHash(
claim *inactivity.Claim,
) (inactivity.ClaimSignatureHash, error)

// GetInactivityClaimNonce returns inactivity claim nonce for the given
// wallet.
GetInactivityClaimNonce(walletID [32]byte) (*big.Int, error)
}

// DKGChainResultHash represents a hash of the DKGChainResult. The algorithm
// used is specific to the chain.
type DKGChainResultHash [32]byte
Expand Down Expand Up @@ -461,6 +466,7 @@ type Chain interface {
sortition.Chain
GroupSelectionChain
DistributedKeyGenerationChain
InactivityClaimChain
BridgeChain
WalletProposalValidatorChain
}
9 changes: 5 additions & 4 deletions pkg/tbtc/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,15 @@ func (lc *localChain) DKGParameters() (*DKGParameters, error) {
}

func (lc *localChain) CalculateInactivityClaimSignatureHash(
nonce *big.Int,
walletPublicKey *ecdsa.PublicKey,
inactiveMembersIndexes []group.MemberIndex,
heartbeatFailed bool,
claim *inactivity.Claim,
) (inactivity.ClaimSignatureHash, error) {
panic("unsupported")
}

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

func (lc *localChain) PastDepositRevealedEvents(
filter *DepositRevealedEventFilter,
) ([]*DepositRevealedEvent, error) {
Expand Down
4 changes: 4 additions & 0 deletions pkg/tbtc/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,12 @@ func (ha *heartbeatAction) execute() error {
// The value of consecutive heartbeat failures exceeds the threshold.
// Proceed with operator inactivity notification.
err = ha.inactivityClaimExecutor.publishClaim(
// Leave the list empty. Some operators were inactive during the
// heartbeat because they were simply unstaking and therefore should not
// be punished.
[]group.MemberIndex{},
true,
messageToSign,
)
if err != nil {
return fmt.Errorf(
Expand Down
14 changes: 4 additions & 10 deletions pkg/tbtc/heartbeat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ func TestHeartbeatAction_HappyPath(t *testing.T) {
hostChain.setHeartbeatProposalValidationResult(proposal, true)

mockExecutor := &mockHeartbeatSigningExecutor{}
inactivityNotifier := newInactivityClaimExecutor(
hostChain,
[]*signer{},
)
inactivityClaimExecutor := &inactivityClaimExecutor{}
action := newHeartbeatAction(
logger,
hostChain,
Expand All @@ -55,7 +52,7 @@ func TestHeartbeatAction_HappyPath(t *testing.T) {
mockExecutor,
proposal,
&heartbeatFailureCounter,
inactivityNotifier,
inactivityClaimExecutor,
startBlock,
expiryBlock,
func(ctx context.Context, blockHeight uint64) error {
Expand Down Expand Up @@ -109,10 +106,7 @@ func TestHeartbeatAction_SigningError(t *testing.T) {
mockExecutor := &mockHeartbeatSigningExecutor{}
mockExecutor.shouldFail = true

inactivityNotifier := newInactivityClaimExecutor(
hostChain,
[]*signer{},
)
inactivityClaimExecutor := &inactivityClaimExecutor{}

action := newHeartbeatAction(
logger,
Expand All @@ -123,7 +117,7 @@ func TestHeartbeatAction_SigningError(t *testing.T) {
mockExecutor,
proposal,
&heartbeatFailureCounter,
inactivityNotifier,
inactivityClaimExecutor,
startBlock,
expiryBlock,
func(ctx context.Context, blockHeight uint64) error {
Expand Down
113 changes: 102 additions & 11 deletions pkg/tbtc/inactivity.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,101 @@ package tbtc

import (
"context"
"fmt"
"math/big"
"sync"

"github.com/ipfs/go-log/v2"
"go.uber.org/zap"
"golang.org/x/sync/semaphore"

"github.com/keep-network/keep-core/pkg/bitcoin"
"github.com/keep-network/keep-core/pkg/generator"
"github.com/keep-network/keep-core/pkg/net"
"github.com/keep-network/keep-core/pkg/protocol/group"
"github.com/keep-network/keep-core/pkg/tecdsa/inactivity"
)

// errInactivityClaimExecutorBusy is an error returned when the inactivity claim
// executor cannot execute the inactivity claim due to another inactivity claim
// execution in progress.
var errInactivityClaimExecutorBusy = fmt.Errorf("inactivity claim executor is busy")

type inactivityClaimExecutor struct {
chain Chain
signers []*signer
lock *semaphore.Weighted

protocolLatch *generator.ProtocolLatch
chain Chain
signers []*signer
broadcastChannel net.BroadcastChannel
membershipValidator *group.MembershipValidator
groupParameters *GroupParameters
protocolLatch *generator.ProtocolLatch

waitForBlockFn waitForBlockFn
}

// TODO Consider moving all inactivity-related code to pkg/protocol/inactivity.
func newInactivityClaimExecutor(
chain Chain,
signers []*signer,
broadcastChannel net.BroadcastChannel,
membershipValidator *group.MembershipValidator,
groupParameters *GroupParameters,
protocolLatch *generator.ProtocolLatch,
waitForBlockFn waitForBlockFn,
) *inactivityClaimExecutor {
return &inactivityClaimExecutor{
chain: chain,
signers: signers,
lock: semaphore.NewWeighted(1),
chain: chain,
signers: signers,
broadcastChannel: broadcastChannel,
membershipValidator: membershipValidator,
groupParameters: groupParameters,
protocolLatch: protocolLatch,
waitForBlockFn: waitForBlockFn,
}
}

func (ice *inactivityClaimExecutor) publishClaim(
inactiveMembersIndexes []group.MemberIndex,
heartbeatFailed bool,
message *big.Int,
) error {
// TODO: Build a claim and launch the publish function for all
// the signers. The value of `heartbeat` should be true and
// `inactiveMembersIndices` should be empty.
if lockAcquired := ice.lock.TryAcquire(1); !lockAcquired {
return errInactivityClaimExecutorBusy
}
defer ice.lock.Release(1)

wallet := ice.wallet()

walletPublicKeyHash := bitcoin.PublicKeyHash(wallet.publicKey)
walletPublicKeyBytes, err := marshalPublicKey(wallet.publicKey)
if err != nil {
return fmt.Errorf("cannot marshal wallet public key: [%v]", err)
}

execLogger := logger.With(
zap.String("wallet", fmt.Sprintf("0x%x", walletPublicKeyBytes)),
)

walletRegistryData, err := ice.chain.GetWallet(walletPublicKeyHash)
if err != nil {
return fmt.Errorf("could not get registry data on wallet: [%v]", err)
}

nonce, err := ice.chain.GetInactivityClaimNonce(
walletRegistryData.EcdsaWalletID,
)
if err != nil {
return fmt.Errorf("could not get nonce for wallet: [%v]", err)
}

claim := &inactivity.Claim{
Nonce: nonce,
WalletPublicKey: wallet.publicKey,
InactiveMembersIndexes: inactiveMembersIndexes,
HeartbeatFailed: heartbeatFailed,
}

wg := sync.WaitGroup{}
wg.Add(len(ice.signers))
Expand All @@ -45,11 +105,37 @@ func (ice *inactivityClaimExecutor) publishClaim(
ice.protocolLatch.Lock()
defer ice.protocolLatch.Unlock()

defer wg.Done()

inactivityClaimTimeoutBlock := uint64(0) // TODO: Set the value of timeout block

go func(signer *signer) {
// TODO: Launch claim publishing for members.
ctx, cancelCtx := withCancelOnBlock(
context.Background(),
inactivityClaimTimeoutBlock,
ice.waitForBlockFn,
)
defer cancelCtx()

ice.publish(
ctx,
execLogger,
message,
signer.signingGroupMemberIndex,
wallet.groupSize(),
wallet.groupDishonestThreshold(
ice.groupParameters.HonestThreshold,
),
ice.membershipValidator,
claim,
)

}(currentSigner)
}

// Wait until all controlled signers complete their routine.
wg.Wait()

return nil
}

Expand All @@ -58,7 +144,6 @@ func (ice *inactivityClaimExecutor) publish(
inactivityLogger log.StandardLogger,
seed *big.Int,
memberIndex group.MemberIndex,
broadcastChannel net.BroadcastChannel,
groupSize int,
dishonestThreshold int,
membershipValidator *group.MembershipValidator,
Expand All @@ -69,7 +154,7 @@ func (ice *inactivityClaimExecutor) publish(
inactivityLogger,
seed.Text(16),
memberIndex,
broadcastChannel,
ice.broadcastChannel,
groupSize,
dishonestThreshold,
membershipValidator,
Expand All @@ -78,3 +163,9 @@ func (ice *inactivityClaimExecutor) publish(
inactivityClaim,
)
}

func (ice *inactivityClaimExecutor) wallet() wallet {
// All signers belong to one wallet. Take that wallet from the
// first signer.
return ice.signers[0].wallet
}
7 changes: 1 addition & 6 deletions pkg/tbtc/inactivity_submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ func (ics *inactivityClaimSigner) SignClaim(claim *inactivity.Claim) (
return nil, fmt.Errorf("result is nil")
}

claimHash, err := ics.chain.CalculateInactivityClaimSignatureHash(
claim.Nonce,
claim.WalletPublicKey,
claim.InactiveMembersIndexes,
claim.HeartbeatFailed,
)
claimHash, err := ics.chain.CalculateInactivityClaimSignatureHash(claim)
if err != nil {
return nil, fmt.Errorf(
"inactivity claim hash calculation failed [%w]",
Expand Down
5 changes: 5 additions & 0 deletions pkg/tbtc/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,11 @@ func (n *node) getInactivityClaimExecutor(
executor := newInactivityClaimExecutor(
n.chain,
signers,
broadcastChannel,
membershipValidator,
n.groupParameters,
n.protocolLatch,
n.waitForBlockHeight,
)

n.inactivityClaimExecutors[executorKey] = executor
Expand Down

0 comments on commit 147d82d

Please sign in to comment.