Skip to content

Commit e2479b0

Browse files
pdp2121JST5000
andauthored
feat: Add enable amendment eta (#169)
## High Level Overview of Change <!-- Please include a summary/list of the changes. If too broad, please consider splitting into multiple PRs. If a relevant Asana task, please link it here. --> Add amendment eta time after majority gained tracking by `amendments_incoming` table. The WebSocket handling process for amendments is now as below: - When ws connection open, subscribe and run ledger_entry once per network via initial node to get amendments already enabled on the network at the time connection starts. - When listening to subscribed ledger stream, when ledger index is flag + 1, send a ledger request with `transactions` and `expand` options set to `true` to scan for `EnableAmendment` transactions (only processed once per network via initial node). - If `EnableAmendment` transaction found: 1. if no Flags, a tx request is sent to retrieve more details about the amendment, a new entry will be added to `amendments_status` table, with `date` field added to reflect the release date, and `eta` removed as the amendment has already been enabled. 2. if Majority Gain Flags, a new `eta` data will be added to `amendments_status` table. 3. if Majority Lost Flags, delete the entry from `amendments_status` table. - Ballots will be received via validation stream on flag - 1. ### Type of Change <!-- Please check relevant options, delete irrelevant ones. --> - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactor (non-breaking change that only restructures code) - [ ] Tests (You added tests for code that already exists, or your new feature included in this PR) - [ ] Documentation Updates - [ ] Release --------- Co-authored-by: Jackson Mills <[email protected]>
1 parent 67955be commit e2479b0

File tree

10 files changed

+192
-120
lines changed

10 files changed

+192
-120
lines changed

ARCHITECTURE.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,18 @@ This table keeps track of the manifests of the validators.
110110
| `seq` |The sequence number of this manifest. |
111111

112112

113-
### `amendments_enabled`
113+
### `amendments_status`
114114

115-
This table keeps track of the amendments enabled on each network.
115+
This table keeps track of the amendments status on each network when either the amendment has been enabled or has reached majority.
116116

117-
| Key | Definition |
118-
|----------------------|----------------------------------------------------------|
119-
| `amendment_id` |The amendment id. |
120-
| `networks` |The network(s) where the amendment has been enabled. |
121-
| `ledger_index` |The ledger where the amendment has been enabled. |
122-
| `tx_hash` |The transaction hash where the amendment has been enabled.|
123-
| `date` |The date and time when the amendment has been enabled. |
117+
| Key | Definition |
118+
|----------------------|-------------------------------------------------------------------|
119+
| `amendment_id` |The amendment id. |
120+
| `networks` |The network(s) where the amendment has been/ will be enabled. |
121+
| `ledger_index` |The ledger where the amendment has been/ will be enabled. |
122+
| `tx_hash` |The transaction hash where the amendment has been/ will be enabled.|
123+
| `eta` |The estimated date and time when the amendment will be enabled. |
124+
| `date` |The date and time when the amendment has been enabled. |
124125

125126

126127
### `amendments_info`

src/api/routes/v1/amendments.ts

+45-27
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Request, Response } from 'express'
33

44
import { getNetworks, query } from '../../../shared/database'
5-
import { AmendmentsInfo } from '../../../shared/types'
5+
import { AmendmentStatus, AmendmentInfo } from '../../../shared/types'
66
import { isEarlierVersion } from '../../../shared/utils'
77
import logger from '../../../shared/utils/logger'
88

@@ -11,22 +11,22 @@ import { CACHE_INTERVAL_MILLIS } from './utils'
1111
interface AmendmentsInfoResponse {
1212
result: 'success' | 'error'
1313
count: number
14-
amendments: AmendmentsInfo[]
14+
amendments: AmendmentInfo[]
1515
}
1616

1717
interface AmendmentsVoteResponse {
1818
result: 'success' | 'error'
1919
count: number
20-
amendments: Array<AmendmentsEnabled | AmendmentInVoting>
20+
amendments: Array<EnabledAmendmentInfo | AmendmentInVoting>
2121
}
2222

2323
interface SingleAmendmentInfoResponse {
2424
result: 'success' | 'error'
25-
amendment: AmendmentsInfo
25+
amendment: AmendmentInfo
2626
}
2727

2828
interface CacheInfo {
29-
amendments: AmendmentsInfo[]
29+
amendments: AmendmentInfo[]
3030
time: number
3131
}
3232

@@ -36,9 +36,10 @@ interface VotingValidators {
3636
unl: boolean
3737
}
3838

39-
interface AmendmentsInfoExtended extends AmendmentsInfo {
39+
interface AmendmentsInfoExtended extends AmendmentInfo {
4040
threshold: string
4141
consensus: string
42+
eta?: Date
4243
}
4344

4445
interface AmendmentInVoting extends AmendmentsInfoExtended {
@@ -54,7 +55,7 @@ interface AmendmentInVotingMap {
5455
}
5556
}
5657

57-
interface AmendmentsEnabled extends AmendmentsInfo {
58+
interface EnabledAmendmentInfo extends AmendmentInfo {
5859
ledger_index?: string
5960
tx_hash?: string
6061
date?: Date
@@ -68,7 +69,7 @@ interface BallotAmendmentDb {
6869
}
6970

7071
interface CacheVote {
71-
networks: Map<string, Array<AmendmentsEnabled | AmendmentInVoting>>
72+
networks: Map<string, Array<EnabledAmendmentInfo | AmendmentInVoting>>
7273
time: number
7374
}
7475

@@ -82,7 +83,7 @@ const cacheInfo: CacheInfo = {
8283
}
8384

8485
const cacheVote: CacheVote = {
85-
networks: new Map<string, Array<AmendmentsEnabled | AmendmentInVoting>>(),
86+
networks: new Map<string, Array<EnabledAmendmentInfo | AmendmentInVoting>>(),
8687
time: Date.now(),
8788
}
8889

@@ -97,8 +98,8 @@ const cacheEnabled = new Map<string, Set<string>>()
9798
* @returns 1 or -1.
9899
*/
99100
function sortByVersion(
100-
prev: AmendmentsInfo | AmendmentInVoting,
101-
next: AmendmentsInfo | AmendmentInVoting,
101+
prev: AmendmentInfo | AmendmentInVoting,
102+
next: AmendmentInfo | AmendmentInVoting,
102103
): number {
103104
if (isEarlierVersion(prev.rippled_version, next.rippled_version)) {
104105
return 1
@@ -129,30 +130,33 @@ void cacheAmendmentsInfo()
129130
* @param id - The network id.
130131
* @returns List of enabled amendments.
131132
*/
132-
async function getEnabledAmendments(id: string): Promise<AmendmentsEnabled[]> {
133-
const enabled = await query('amendments_enabled')
133+
async function getEnabledAmendments(
134+
id: string,
135+
): Promise<EnabledAmendmentInfo[]> {
136+
const enabled = await query('amendments_status')
134137
.leftJoin(
135138
'amendments_info',
136-
'amendments_enabled.amendment_id',
139+
'amendments_status.amendment_id',
137140
'amendments_info.id',
138141
)
139142
.select(
140-
'amendments_enabled.amendment_id AS id',
141-
'amendments_enabled.ledger_index',
142-
'amendments_enabled.tx_hash',
143-
'amendments_enabled.date',
143+
'amendments_status.amendment_id AS id',
144+
'amendments_status.ledger_index',
145+
'amendments_status.tx_hash',
146+
'amendments_status.date',
144147
'amendments_info.name',
145148
'amendments_info.rippled_version',
146149
'amendments_info.deprecated',
147150
)
148-
.where('amendments_enabled.networks', id)
151+
.where('amendments_status.networks', id)
152+
.whereNull('amendments_status.eta')
149153

150154
enabled.sort(sortByVersion)
151155

152156
if (!cacheEnabled.has(id)) {
153157
cacheEnabled.set(id, new Set())
154158
}
155-
enabled.forEach((amendment: AmendmentsEnabled) => {
159+
enabled.forEach((amendment: EnabledAmendmentInfo) => {
156160
cacheEnabled.get(id)?.add(amendment.id)
157161
})
158162

@@ -222,11 +226,12 @@ async function calculateConsensus(
222226
}
223227

224228
/**
225-
* Retrieves amendments enabled on a network.
229+
* Retrieves amendments in voting on a network.
226230
*
227231
* @param id - The network id.
228-
* @returns List of enabled amendments.
232+
* @returns List of amendments in voting.
229233
*/
234+
// eslint-disable-next-line max-lines-per-function, max-statements -- Disabled for this function.
230235
async function getVotingAmendments(id: string): Promise<AmendmentInVoting[]> {
231236
const inNetworks: BallotAmendmentDb[] = await query('ballot')
232237
.leftJoin('validators', 'ballot.signing_key', 'validators.signing_key')
@@ -238,12 +243,24 @@ async function getVotingAmendments(id: string): Promise<AmendmentInVoting[]> {
238243
)
239244
.where('validators.networks', id)
240245

246+
const incomingAmendments: AmendmentStatus[] = await query('amendments_status')
247+
.select('*')
248+
.where('networks', id)
249+
.whereNotNull('eta')
250+
.whereNull('date')
251+
241252
const votingAmendments: AmendmentInVotingMap = {}
242253

243254
inNetworks.forEach((val) => {
244255
parseAmendmentVote(val, votingAmendments)
245256
})
246257

258+
for (const amendment of incomingAmendments) {
259+
if (amendment.amendment_id in votingAmendments) {
260+
votingAmendments[amendment.amendment_id].eta = amendment.eta
261+
}
262+
}
263+
247264
if (Date.now() - cacheInfo.time > CACHE_INTERVAL_MILLIS) {
248265
await cacheAmendmentsInfo()
249266
}
@@ -267,6 +284,7 @@ async function getVotingAmendments(id: string): Promise<AmendmentInVoting[]> {
267284
deprecated: value.deprecated,
268285
threshold: value.threshold,
269286
consensus: value.consensus,
287+
eta: value.eta,
270288
voted: {
271289
count: value.validators.length,
272290
validators: value.validators,
@@ -317,7 +335,7 @@ export async function handleAmendmentsInfo(
317335
if (Date.now() - cacheInfo.time > CACHE_INTERVAL_MILLIS) {
318336
await cacheAmendmentsInfo()
319337
}
320-
const amendments: AmendmentsInfo[] = cacheInfo.amendments
338+
const amendments: AmendmentInfo[] = cacheInfo.amendments
321339
const response: AmendmentsInfoResponse = {
322340
result: 'success',
323341
count: amendments.length,
@@ -346,7 +364,7 @@ export async function handleAmendmentInfo(
346364
if (Date.now() - cacheInfo.time > CACHE_INTERVAL_MILLIS) {
347365
await cacheAmendmentsInfo()
348366
}
349-
const amendments: AmendmentsInfo[] = cacheInfo.amendments.filter(
367+
const amendments: AmendmentInfo[] = cacheInfo.amendments.filter(
350368
(amend) => amend.name === param || amend.id === param,
351369
)
352370
if (amendments.length === 0) {
@@ -390,7 +408,7 @@ export async function handleAmendmentsVote(
390408
await cacheAmendmentsVote()
391409
}
392410
const networkVotes:
393-
| Array<AmendmentsEnabled | AmendmentInVoting>
411+
| Array<EnabledAmendmentInfo | AmendmentInVoting>
394412
| undefined = cacheVote.networks.get(network)
395413
if (networkVotes) {
396414
const response: AmendmentsVoteResponse = {
@@ -423,14 +441,14 @@ export async function handleAmendmentVote(
423441
await cacheAmendmentsVote()
424442
}
425443
const networkVotes:
426-
| Array<AmendmentsEnabled | AmendmentInVoting>
444+
| Array<EnabledAmendmentInfo | AmendmentInVoting>
427445
| undefined = cacheVote.networks.get(network)
428446
if (networkVotes === undefined) {
429447
res.send({ result: 'error', message: 'network not found' })
430448
}
431449

432450
const amendment = (
433-
networkVotes as Array<AmendmentsEnabled | AmendmentInVoting>
451+
networkVotes as Array<EnabledAmendmentInfo | AmendmentInVoting>
434452
).filter((amend) => amend.id === identifier || amend.name === identifier)
435453

436454
if (amendment.length > 0) {

src/connection-manager/connections.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ async function setHandlers(
7676
}
7777
if (data.result?.node) {
7878
void handleWsMessageLedgerEntryAmendments(
79-
ws,
8079
data as LedgerEntryResponse,
8180
networks,
8281
)
83-
} else if (data.result?.ledger) {
82+
} else if (data.result?.ledger && isInitialNode) {
8483
void handleWsMessageLedgerEnableAmendments(
8584
ws,
8685
data as LedgerResponseCorrected,
86+
networks,
8787
)
8888
} else if (data.result?.Amendment) {
8989
void handleWsMessageTxEnableAmendments(data as TxResponse, networks)
@@ -93,6 +93,7 @@ async function setHandlers(
9393
ledger_hashes,
9494
networks,
9595
networkFee,
96+
ws,
9697
)
9798
}
9899
})

0 commit comments

Comments
 (0)