Skip to content

Commit

Permalink
Merge branch 'main' into heartbeats-update
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaszslabon committed May 13, 2024
2 parents 60da8cc + a3904dd commit 4e32ec6
Show file tree
Hide file tree
Showing 19 changed files with 960 additions and 124 deletions.
5 changes: 2 additions & 3 deletions cmd/maintainercli.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,12 @@ var listDepositsCommand = cobra.Command{

func printDepositsTable(deposits []*tbtcpg.Deposit) error {
w := tabwriter.NewWriter(os.Stdout, 2, 4, 1, ' ', tabwriter.AlignRight)
fmt.Fprintf(w, "index\twallet\ttype\tvalue (BTC)\tdeposit key\trevealed deposit data\tconfirmations\tswept\t\n")
fmt.Fprintf(w, "index\twallet\tvalue (BTC)\tdeposit key\trevealed deposit data\tconfirmations\tswept\t\n")

for i, deposit := range deposits {
fmt.Fprintf(w, "%d\t%s\t%s\t%.5f\t%s\t%s\t%d\t%t\t\n",
fmt.Fprintf(w, "%d\t%s\t%.5f\t%s\t%s\t%d\t%t\t\n",
i,
hexutils.Encode(deposit.WalletPublicKeyHash[:]),
deposit.ScriptType,
deposit.AmountBtc,
deposit.DepositKey,
fmt.Sprintf(
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ require (
github.com/ipfs/go-log v1.0.5
github.com/ipfs/go-log/v2 v2.5.1
github.com/jbenet/goprocess v0.1.4
github.com/keep-network/keep-common v1.7.1-0.20231107101149-559db3d3849e
github.com/keep-network/keep-common v1.7.1-0.20240424094333-bd36cd25bb74
github.com/libp2p/go-addr-util v0.2.0
github.com/libp2p/go-libp2p v0.32.2
github.com/libp2p/go-libp2p-kad-dht v0.25.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa h1:AKTJr+STc4rP9NcN2ppP9Zft3GbYechFW8q/S8UNQrQ=
github.com/keep-network/go-electrum v0.0.0-20240206170935-6038cb594daa/go.mod h1:eiMFzdvS+x8Voi0bmiZtVfJ3zMNRUnPNDnhCQR0tudo=
github.com/keep-network/keep-common v1.7.1-0.20231107101149-559db3d3849e h1:6kXLtv3TfObPoBNSAMqpMefOyK01y6X4zghau6F5NDg=
github.com/keep-network/keep-common v1.7.1-0.20231107101149-559db3d3849e/go.mod h1:OmaZrnZODf6RJ95yUn2kBjy8Z4u2npPJQkSiyimluto=
github.com/keep-network/keep-common v1.7.1-0.20240424094333-bd36cd25bb74 h1:cG2BiQJj6+v86duIAuDd6sPJZqLVWaOPxzt3nWQQaAo=
github.com/keep-network/keep-common v1.7.1-0.20240424094333-bd36cd25bb74/go.mod h1:OmaZrnZODf6RJ95yUn2kBjy8Z4u2npPJQkSiyimluto=
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ configMapGenerator:
- name: tbtc-v2-monitoring-config
literals:
- environment=mainnet
- large-deposit-threshold-sat=1000000000 # 10 BTC
- large-deposit-threshold-sat=10000000000 # 100 BTC
- large-redemption-threshold-sat=10000000000 # 100 BTC

secretGenerator:
- name: tbtc-v2-monitoring-config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ configMapGenerator:
- name: tbtc-v2-monitoring-config
literals:
- environment=testnet
- large-deposit-threshold-sat=10000000 # 0.1 BTC for testing purposes
- large-deposit-threshold-sat=1000000000 # 10 BTC
- large-redemption-threshold-sat=1000000000 # 10 BTC

secretGenerator:
- name: tbtc-v2-monitoring-config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ spec:
configMapKeyRef:
name: tbtc-v2-monitoring-config
key: large-deposit-threshold-sat
- name: LARGE_REDEMPTION_THRESHOLD_SAT
valueFrom:
configMapKeyRef:
name: tbtc-v2-monitoring-config
key: large-redemption-threshold-sat
- name: DATA_DIR_PATH
value: /mnt/tbtc-v2-monitoring/data
- name: SENTRY_DSN
Expand Down
60 changes: 57 additions & 3 deletions pkg/bitcoin/electrum/electrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,18 @@ func (c *Connection) GetTransaction(
// We cannot use `GetTransaction` to get the the transaction details
// as Esplora/Electrs doesn't support verbose transactions.
// See: https://github.com/Blockstream/electrs/pull/36
return client.GetRawTransaction(ctx, txID)
tx, err := client.GetRawTransaction(ctx, txID)
if err != nil {
if isTxNotFoundErr(err) {
// The transaction was not found on the chain. There is
// no point in retrying the request and losing time.
return "", nil
}

return "", err
}

return tx, nil
},
"GetRawTransaction",
)
Expand All @@ -99,6 +110,13 @@ func (c *Connection) GetTransaction(
err,
)
}
if len(rawTransaction) == 0 {
return nil, fmt.Errorf(
"failed to get raw transaction with ID [%s]: [%v]",
txID,
fmt.Errorf("not found"),
)
}

result, err := convertRawTransaction(rawTransaction)
if err != nil {
Expand All @@ -123,10 +141,21 @@ func (c *Connection) GetTransactionConfirmations(
rawTransaction, err := requestWithRetry(
c,
func(ctx context.Context, client *electrum.Client) (string, error) {
// We cannot use `GetTransaction` to get the the transaction details
// We cannot use `GetTransaction` to get the transaction details
// as Esplora/Electrs doesn't support verbose transactions.
// See: https://github.com/Blockstream/electrs/pull/36
return client.GetRawTransaction(ctx, txID)
tx, err := client.GetRawTransaction(ctx, txID)
if err != nil {
if isTxNotFoundErr(err) {
// The transaction was not found on the chain. There is
// no point in retrying the request and losing time.
return "", nil
}

return "", err
}

return tx, nil
},
"GetRawTransaction",
)
Expand All @@ -138,6 +167,13 @@ func (c *Connection) GetTransactionConfirmations(
err,
)
}
if len(rawTransaction) == 0 {
return 0, fmt.Errorf(
"failed to get raw transaction with ID [%s]: [%v]",
txID,
fmt.Errorf("not found"),
)
}

tx, err := decodeTransaction(rawTransaction)
if err != nil {
Expand Down Expand Up @@ -224,6 +260,24 @@ txOutLoop:
return 0, nil
}

func isTxNotFoundErr(err error) bool {
txNotFoundErrs := []string{
"no such mempool or blockchain transaction",
"missing transaction",
"transaction not found",
}

errStr := strings.ToLower(err.Error())

for _, txNotFoundErr := range txNotFoundErrs {
if strings.Contains(errStr, txNotFoundErr) {
return true
}
}

return false
}

// BroadcastTransaction broadcasts the given transaction over the
// network of the Bitcoin chain nodes. If the broadcast action could not be
// done, this function returns an error. This function does not give any
Expand Down
63 changes: 25 additions & 38 deletions pkg/bitcoin/electrum/electrum_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"math"
"reflect"
"sort"
"strings"
"testing"
Expand Down Expand Up @@ -175,15 +176,19 @@ func TestGetTransaction_Negative_Integration(t *testing.T) {

_, err := electrum.GetTransaction(invalidTxID)

assertMissingTransactionError(
t,
testConfig.clientConfig,
fmt.Sprintf(
"failed to get raw transaction with ID [%s]",
invalidTxID.Hex(bitcoin.ReversedByteOrder),
),
err,
expectedErr := fmt.Errorf(
"failed to get raw transaction with ID [%s]: [not found]",
invalidTxID.Hex(bitcoin.ReversedByteOrder),
)
if !reflect.DeepEqual(expectedErr, err) {
t.Errorf(
"unexpected error\n"+
"expected: %v\n"+
"actual: %v\n",
expectedErr,
err,
)
}
})
}

Expand Down Expand Up @@ -221,15 +226,19 @@ func TestGetTransactionConfirmations_Negative_Integration(t *testing.T) {

_, err := electrum.GetTransactionConfirmations(invalidTxID)

assertMissingTransactionError(
t,
testConfig.clientConfig,
fmt.Sprintf(
"failed to get raw transaction with ID [%s]",
invalidTxID.Hex(bitcoin.ReversedByteOrder),
),
err,
expectedErr := fmt.Errorf(
"failed to get raw transaction with ID [%s]: [not found]",
invalidTxID.Hex(bitcoin.ReversedByteOrder),
)
if !reflect.DeepEqual(expectedErr, err) {
t.Errorf(
"unexpected error\n"+
"expected: %v\n"+
"actual: %v\n",
expectedErr,
err,
)
}
})
}

Expand Down Expand Up @@ -607,17 +616,11 @@ func assertNumberCloseTo(t *testing.T, expected uint, actual uint, delta uint) {
}

type expectedErrorMessages struct {
missingTransaction []string
missingBlockHeader []string
missingTransactionInBlock []string
}

var expectedServerErrorMessages = expectedErrorMessages{
missingTransaction: []string{
"errNo: 0, errMsg: missing transaction",
"errNo: 2, errMsg: daemon error: DaemonError({'code': -5, 'message': 'No such mempool or blockchain transaction. Use gettransaction for wallet transactions.'})",
"errNo: 2, errMsg: daemon error: DaemonError({'message': 'Transaction not found.', 'code': -1})",
},
missingBlockHeader: []string{
"errNo: 0, errMsg: missing header",
"errNo: 1, errMsg: height 4,294,967,295 out of range",
Expand All @@ -629,22 +632,6 @@ var expectedServerErrorMessages = expectedErrorMessages{
"errNo: 1, errMsg: No transaction matching the requested hash found at height 123456"},
}

func assertMissingTransactionError(
t *testing.T,
clientConfig electrum.Config,
clientErrorPrefix string,

actualError error,
) {
assertServerError(
t,
clientConfig,
clientErrorPrefix,
expectedServerErrorMessages.missingTransaction,
actualError,
)
}

func assertMissingBlockHeaderError(
t *testing.T,
clientConfig electrum.Config,
Expand Down
50 changes: 37 additions & 13 deletions pkg/chain/ethereum/tbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"sort"
"time"

"github.com/keep-network/keep-common/pkg/cache"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -41,6 +43,10 @@ const (
WalletProposalValidatorContractName = "WalletProposalValidator"
)

const (
sweptDepositsCachePeriod = 7 * 24 * time.Hour
)

// TbtcChain represents a TBTC-specific chain handle.
type TbtcChain struct {
*baseChain
Expand All @@ -51,6 +57,8 @@ type TbtcChain struct {
sortitionPool *ecdsacontract.EcdsaSortitionPool
walletProposalValidator *tbtccontract.WalletProposalValidator
redemptionWatchtower *tbtccontract.RedemptionWatchtower

sweptDepositsCache *cache.GenericTimeCache[*tbtc.DepositChainRequest]
}

// NewTbtcChain construct a new instance of the TBTC-specific Ethereum
Expand Down Expand Up @@ -238,6 +246,7 @@ func newTbtcChain(
sortitionPool: sortitionPool,
walletProposalValidator: walletProposalValidator,
redemptionWatchtower: redemptionWatchtower,
sweptDepositsCache: cache.NewGenericTimeCache[*tbtc.DepositChainRequest](sweptDepositsCachePeriod),
}, nil
}

Expand Down Expand Up @@ -1308,8 +1317,14 @@ func (tc *TbtcChain) GetDepositRequest(
fundingOutputIndex uint32,
) (*tbtc.DepositChainRequest, bool, error) {
depositKey := buildDepositKey(fundingTxHash, fundingOutputIndex)
depositCacheKey := depositKey.Text(16)

tc.sweptDepositsCache.Sweep()
if cachedRequest, ok := tc.sweptDepositsCache.Get(depositCacheKey); ok {
return cachedRequest, true, nil
}

depositRequest, err := tc.bridge.Deposits(depositKey)
chainRequest, err := tc.bridge.Deposits(depositKey)
if err != nil {
return nil, false, fmt.Errorf(
"cannot get deposit request for key [0x%x]: [%v]",
Expand All @@ -1319,30 +1334,39 @@ func (tc *TbtcChain) GetDepositRequest(
}

// Deposit not found.
if depositRequest.RevealedAt == 0 {
if chainRequest.RevealedAt == 0 {
return nil, false, nil
}

var vault *chain.Address
if depositRequest.Vault != [20]byte{} {
v := chain.Address(depositRequest.Vault.Hex())
if chainRequest.Vault != [20]byte{} {
v := chain.Address(chainRequest.Vault.Hex())
vault = &v
}

var extraData *[32]byte
if depositRequest.ExtraData != [32]byte{} {
extraData = &depositRequest.ExtraData
if chainRequest.ExtraData != [32]byte{} {
extraData = &chainRequest.ExtraData
}

return &tbtc.DepositChainRequest{
Depositor: chain.Address(depositRequest.Depositor.Hex()),
Amount: depositRequest.Amount,
RevealedAt: time.Unix(int64(depositRequest.RevealedAt), 0),
request := &tbtc.DepositChainRequest{
Depositor: chain.Address(chainRequest.Depositor.Hex()),
Amount: chainRequest.Amount,
RevealedAt: time.Unix(int64(chainRequest.RevealedAt), 0),
Vault: vault,
TreasuryFee: depositRequest.TreasuryFee,
SweptAt: time.Unix(int64(depositRequest.SweptAt), 0),
TreasuryFee: chainRequest.TreasuryFee,
SweptAt: time.Unix(int64(chainRequest.SweptAt), 0),
ExtraData: extraData,
}, true, nil
}

// If the request was swept on-chain, there is a guarantee that no
// further changes will occur regarding its parameters.
// Such a request can be cached.
if isSwept := request.SweptAt.Unix() != 0; isSwept {
tc.sweptDepositsCache.Add(depositCacheKey, request)
}

return request, true, nil
}

func (tc *TbtcChain) PastNewWalletRegisteredEvents(
Expand Down
Loading

0 comments on commit 4e32ec6

Please sign in to comment.