Skip to content

Commit

Permalink
Merge branch 'main' into validate-transaction-proof
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-zimnoch authored Mar 10, 2023
2 parents c673dca + bb70626 commit 9acd6fe
Show file tree
Hide file tree
Showing 42 changed files with 7,655 additions and 2,952 deletions.
18 changes: 9 additions & 9 deletions docs/rfc/rfc-7.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ progress, the signing group members proceed with tECDSA signing protocol.

Each UTXO being an input to the sweep transaction is unlocked sequentially in
a separate signing session. Each signing session begins with an announcement
phase allowing to exclude offline operators. There is a 30-blocks (~6 minutes)
phase allowing to exclude offline operators. There is a 36-blocks (~7 minutes)
timeout for each signing attempt.

If the given signing attempt fails for any reason (error or timeout), the next
attempt starts exactly 30 blocks after the previous one started.
attempt starts exactly 41 blocks after the previous one started.

All signers selected for the given signing attempt must confirm successful
execution by sending a message with the produced signature over the broadcast
Expand All @@ -200,8 +200,8 @@ client works on a 2-core machine and there are no more than 5 signing group
members on a single machine, the bottleneck phase should take no more than
1 minute.

The announcement phase takes always 7 blocks, so ~1.5 minutes assuming 12s block
time. With 30 blocks timeout for a single attempt, it leaves more than 3 minutes
The announcement phase takes always 6 blocks, so 1min 12s assuming 12s block
time. With 36 blocks timeout for a single attempt, it leaves more than 6 minutes
for the rest of the signing protocol which should be more than enough.
This should also be enough for local development when all signing group members
reside on the same computer. Based on the local benchmarks, the entire signing
Expand All @@ -221,23 +221,23 @@ corrupted data:

- With 1 malicious member in a signing group, we need 2 attempts of the protocol
in the worst case (`P = (99 choose 51) / (100 choose 51) = 0.49`).
In the worst case, it takes approximately 2h 30min to sign 15 inputs.
In the worst case, it takes approximately 3h 30min to sign 15 inputs.

- With 2 malicious members in a signing group, we need 5 attempts of the protocol
in the worst case (`P = (98 choose 51) / (100 choose 51) = 0.2375757575`).
In the worst case, it takes approximately 7h 30min to sign 15 inputs.
In the worst case, it takes approximately 8h 45min to sign 15 inputs.

- With 3 malicious members in a signing group, we need 10 attempts of the protocol
in the worst case (`P = (97 choose 51) / (100 choose 51) = 0.1139393939`).
In the worst case, it takes approximately 15h to sign 15 inputs.
In the worst case, it takes approximately 17h 30min to sign 15 inputs.

- With 4 malicious members in a signing group, we need 20 attempts of the
protocol in the worst case (`P = (96 choose 51) / (100 choose 51) = 0.0540331146`).
In the worst case, it takes approximately 30h to sign 15 inputs.
In the worst case, it takes approximately 35h to sign 15 inputs.

- With 5 malicious members in a signing group, we need 40 attempts of the protocol
in the worst case (`P = (95 choose 51) / (100 choose 51) = 0.0253280224`).
In the worst case, it takes approximately 60h to sign 15 inputs.
In the worst case, it takes approximately 70h to sign 15 inputs.

This attack slows down the sweeping schedule but given that the active wallet is
not performing redemptions or moving funds, it does not affect the funds already
Expand Down
428 changes: 428 additions & 0 deletions docs/rfc/rfc-8.adoc

Large diffs are not rendered by default.

35 changes: 34 additions & 1 deletion monitoring/docs/monitoring-and-telemetry.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,18 @@ events produced by the monitoring component are:

* deposit revealed,
* wallet registered,
* DKG result submitted,
* DKG result approved,
* DKG result challenged,
* large deposit revealed,
* optimistic minting canceled,
* optimistic minting requested too early,
* optimistic minting requested for undetermined Bitcoin transaction,
* optimistic minting not requested by designated minter,
* optimistic minting not finalized by designated minter,
* optimistic minting not requested by any minter,
* optimistic minting not finalized by any minter.
* optimistic minting not finalized by any minter,
* high TBTC token total supply change.

==== Deposit revealed

Expand All @@ -133,6 +137,26 @@ An *informational system event* indicating that a new wallet was registered
on the on-chain Bridge contract. This event is directly sent to Discord as a
notification that does not require any action.

==== DKG result submitted

An *informational system event* indicating that a new DKG result was submitted
to the on-chain WalletRegistry contract. This event is directly sent to Discord
as a notification that does not require any action.

==== DKG result approved

An *informational system event* indicating that the submitted DKG result was
approved on the on-chain WalletRegistry contract. This event is directly sent to
Discord as a notification that does not require any action.

==== DKG result challenged

A *critical system event* indicating that the submitted DKG result was
challenged on the on-chain WalletRegistry contract. This event is sent to
Sentry hub and requires an immediate team’s action. The default action is
checking the reason of the challenge as that event may indicate a malicious
wallet operator or a serious bug in the off-chain client code.

==== Large deposit revealed

A *warning system event* indicating that a large deposit was revealed to the
Expand Down Expand Up @@ -199,6 +223,15 @@ attention. The default action is investigating the cause of the minters idleness
as the underlying deposit may be invalid, minters may be unhealthy/malicious or
there may be a bug in the minters bot code.

==== High TBTC token total supply change

A *critical system event* indicating that a high change (i.e. >=10%) of the
total TBTC v2 token supply took place in the last 12 hours. This event is sent
to Sentry hub and requires an immediate team’s action. The default action is
checking the root cause of the supply change and making sure its source is
actually a proper deposit/redemption and there are no signs of any malicious
action.

== Sentry hub

The monitoring and telemetry system uses Sentry as hub for relevant monitoring
Expand Down
22 changes: 19 additions & 3 deletions monitoring/src/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { EthereumBridge, EthereumTBTCVault } from "@keep-network/tbtc-v2.ts"
import {
EthereumBridge,
EthereumTBTCToken,
EthereumTBTCVault,
} from "@keep-network/tbtc-v2.ts"
import { providers } from "ethers"

import { context, Environment } from "./context"

import type { Bridge, TBTCVault } from "@keep-network/tbtc-v2.ts/dist/src/chain"
import type {
Bridge,
TBTCVault,
TBTCToken,
} from "@keep-network/tbtc-v2.ts/dist/src/chain"

const resolve = () => {
let packageName: string
Expand Down Expand Up @@ -47,7 +55,15 @@ const resolve = () => {
deployedAtBlockNumber: tbtcVaultArtifact.receipt.blockNumber,
})

return { bridge, tbtcVault, latestBlock }
// eslint-disable-next-line @typescript-eslint/no-var-requires,global-require,import/no-dynamic-require
const tbtcTokenArtifact = require(`${packageName}/artifacts/TBTC.json`)
const tbtcToken: TBTCToken = new EthereumTBTCToken({
address: tbtcTokenArtifact.address,
signerOrProvider: provider,
deployedAtBlockNumber: tbtcTokenArtifact.receipt.blockNumber,
})

return { bridge, tbtcVault, tbtcToken, latestBlock }
}

export const contracts = resolve()
50 changes: 41 additions & 9 deletions monitoring/src/file-persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import { Config, JsonDB } from "node-json-db"

import { context } from "./context"

import type { SupplyMonitorPersistence } from "./supply-monitor"
import type {
Persistence as SystemEventPersistence,
ReceiverId as SystemEventReceiverId,
SystemEvent,
} from "./system-event"

const checkpointBlockPath = "/checkpointBlock"
const handledSystemEventsPath = "/handledSystemEvents"
export class SystemEventFilePersistence implements SystemEventPersistence {
private readonly checkpointBlockPath = "/checkpointBlock"

private readonly handledSystemEventsPath = "/handledSystemEvents"

export class FilePersistence implements SystemEventPersistence {
private db: JsonDB

constructor() {
Expand All @@ -21,26 +23,26 @@ export class FilePersistence implements SystemEventPersistence {
}

async checkpointBlock(): Promise<number> {
if (!(await this.db.exists(checkpointBlockPath))) {
if (!(await this.db.exists(this.checkpointBlockPath))) {
return 0
}

return this.db.getObject<number>(checkpointBlockPath)
return this.db.getObject<number>(this.checkpointBlockPath)
}

async updateCheckpointBlock(block: number): Promise<void> {
await this.db.push(checkpointBlockPath, block)
await this.db.push(this.checkpointBlockPath, block)
}

async handledSystemEvents(): Promise<
Record<SystemEventReceiverId, SystemEvent[]>
> {
if (!(await this.db.exists(handledSystemEventsPath))) {
if (!(await this.db.exists(this.handledSystemEventsPath))) {
return {}
}

return this.db.getObject<Record<SystemEventReceiverId, SystemEvent[]>>(
handledSystemEventsPath
this.handledSystemEventsPath
)
}

Expand All @@ -55,6 +57,36 @@ export class FilePersistence implements SystemEventPersistence {
handledSystemEvents[receiverId].push(...systemEvents[receiverId])
})

await this.db.push(handledSystemEventsPath, handledSystemEvents)
await this.db.push(this.handledSystemEventsPath, handledSystemEvents)
}
}

export class SupplyMonitorFilePersistence implements SupplyMonitorPersistence {
private readonly lastHighTotalSupplyChangeBlockPath =
"/lastHighTotalSupplyChangeBlock"

private db: JsonDB

constructor() {
this.db = new JsonDB(
new Config(
`${context.dataDirPath}/supply-monitor-db.json`,
true,
true,
"/"
)
)
}

async lastHighTotalSupplyChangeBlock(): Promise<number> {
if (!(await this.db.exists(this.lastHighTotalSupplyChangeBlockPath))) {
return 0
}

return this.db.getObject<number>(this.lastHighTotalSupplyChangeBlockPath)
}

async updateLastHighTotalSupplyChangeBlock(block: number): Promise<void> {
await this.db.push(this.lastHighTotalSupplyChangeBlockPath, block)
}
}
15 changes: 11 additions & 4 deletions monitoring/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import { DepositMonitor } from "./deposit-monitor"
import { contracts } from "./contracts"
import { DiscordReceiver } from "./discord-receiver"
import { SentryReceiver } from "./sentry-receiver"
import { FilePersistence } from "./file-persistence"
import {
SupplyMonitorFilePersistence,
SystemEventFilePersistence,
} from "./file-persistence"
import { context } from "./context"
import { MintingMonitor } from "./minting-monitor"
import { WalletMonitor } from "./wallet-monitor"
import { SupplyMonitor } from "./supply-monitor"

import type { Client as BitcoinClient } from "@keep-network/tbtc-v2.ts/dist/src/bitcoin"
import type {
Expand All @@ -21,6 +25,7 @@ const btcClient: BitcoinClient = ElectrumClient.fromUrl(context.electrumUrl)
const monitors: SystemEventMonitor[] = [
new DepositMonitor(contracts.bridge),
new MintingMonitor(contracts.bridge, contracts.tbtcVault, btcClient),
new SupplyMonitor(contracts.tbtcToken, new SupplyMonitorFilePersistence()),
new WalletMonitor(contracts.bridge),
]

Expand All @@ -40,9 +45,11 @@ const receivers: SystemEventReceiver[] = ((): SystemEventReceiver[] => {
return registered
})()

const persistence = new FilePersistence()

const manager = new SystemEventManager(monitors, receivers, persistence)
const manager = new SystemEventManager(
monitors,
receivers,
new SystemEventFilePersistence()
)

manager.trigger().then((report) => {
switch (report.status) {
Expand Down
Loading

0 comments on commit 9acd6fe

Please sign in to comment.