Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds support for fetching account tx by range #5694

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -428,5 +428,114 @@
}
]
}
],
"Route wallet/getAccountTransactions streams back transactions for a given block sequence range": [
{
"value": {
"encrypted": false,
"version": 4,
"id": "c2ae9a9c-cd0e-495d-b17a-52ca90119315",
"name": "sequence-range",
"spendingKey": "32c8929c43e7eafe851dd620311e6ac3a2bb65089b5ab6cf1345bed578ffc6ce",
"viewKey": "6daf00a551700c030ad186f7bbd2487d0653d05df5d4ed1ffad182068829123ce13fd1d96e840ac3fdd1671f35f097bc09d16dc9ad8e02c8b700840cdc45406c",
"incomingViewKey": "d9850f564e80af3cc3e0c82c9946add6c5557276bb8b02d41519c4894ba57e00",
"outgoingViewKey": "77d6fd2b8f537216c5587c02e29ee08e1e161ffe0a8eb82ba5bdf6fa913d0346",
"publicAddress": "135126152374e9d1101f20c7463b0a9017935265ade5efa9201ec3b0d61694d7",
"createdAt": {
"sequence": 3,
"hash": {
"type": "Buffer",
"data": "base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"scanningEnabled": true,
"proofAuthorizingKey": "0ce6a7bb77afb3d69e0ea6010de24640ca544d5beb1a13dd2f46e9c64637d703"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:pNbbBr/Y5tiJAMwxnkbM8z+uZlDeKdOpVJoOLDAAGJI="
},
"sequence": 3
}
},
{
"header": {
"sequence": 4,
"previousBlockHash": "A4D6DB06BFD8E6D88900CC319E46CCF33FAE6650DE29D3A9549A0E2C30001892",
"noteCommitment": {
"type": "Buffer",
"data": "base64:rlq+oYflawkbjDFVWTpFYH2mbODcdfirePzTjGF4DmY="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:HBGrpmMARUdBaSVnzPsKqXJkxKHo8OV7h4qkYwPZPFU="
},
"target": "9730709775814189186457169137146237252531269575936492615916813051127375",
"randomness": "0",
"timestamp": 1733958144507,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 7,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAO719l2a2Ac1XknImsXoAuAlT5+tIbZ0awTQLsmeUf12igwV5mZpewD6q9s0t0Py6rh6m8Mmg8SPU692FSBFRcwJpkN6+jEdhQoWvJaZ7pku4Io5K/B/Tu8CvRxSh92ttkKeWQTEAvvkPRJYenw/aUZJoyMK49/qtKTDfmVtofo8WjzOnxgZsHrWUeg2mESvs5m7NkUHgOmSg1wOpO/+v70a+m5IBz/taDH050wcvkSWlVwItfrlwEcK/My7ta+UKV/4xG/l9AzY92+ne3/8C37rxdO68obrEvi1wOfuOUu1TteNyMN4rbWM+PKaKvwNRParN8o17BcOW1tlcCQwEXXTyv2+Qt/WAtPo/phMl8lbWWOF0mx9jA8ZW/qnlDI8KayN7ru2B1EgSOjupqMo0LOprdQAI6aANxwv52sSgvO4Uzj6/MsnVYlNIWKiVnA/NG9RXxu6iXNr9hwLW5po3TGUSrig+TuH5aDO+jM/ms3EpmzAqU6vxmYZt1MrvlSwiP/HeokexI9OJ/WFEfidxJsazxu1aKg9tSiYeJMPZAb6JQXaeTks2ky0WsYTq/7boxJjD8I7vhj415UOEh8e5oyamNtYnjE8NnJtgvwNEU2RagE021yMZ20lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwsbnYBTqjLX4da9zrX6EBNpuu63spYFsiLvT3+Hmh7+lR65WjxGw07LFvMDhgEogQ2yGGgmWD3a5g1dm8GuNnBw=="
}
]
},
{
"header": {
"sequence": 5,
"previousBlockHash": "C3A96977F57F287DCC75F652669C8C93BDE9B3AC875683234B57ED0B8EDEA09A",
"noteCommitment": {
"type": "Buffer",
"data": "base64:lp/mNzIiYt8RtDKRdRHASWyejigbcjhmssbYQ8Q4BSI="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:EVkHc9/HuS4tUevIhoYR68jdatqlBh2h76juVr3Tgd0="
},
"target": "9702286958231331178817990090815412930753364059255073544208338923526689",
"randomness": "0",
"timestamp": 1733958145094,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 8,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAjT5rD2IFY3gcEbbFd9LgHzRJ9CXaAyDK0MkUcBPIbFqK0EjqIpYOhXAWk7JxQlMtVI1iYZVhrMCVL1DcBe2G7AFSPGT/RgenPBXLhsxnDH+LrI+SXktcWQHmNzzbd5azGlFRBpfh0DgFBGhKPa93IijLllP0d95L6HoRj5R9vFkCf7Z/vv/hfyQf+taN02qd4Yfd1KOHX0rn1OaGgCQuKPYWKoSvJkMcOrGAVLvUc2yjRQrWHjbdZiPBhDe8wlgyqom7Xh8+NMTjTGQKt0uyXzu8SbdkU88xVDhZ0bgMlWT2qmqI0vjq+RUCOOs81JYRE19vddoJ8bcNv/IuRXNzod1ZeknYyoDXOInKsIhs01qg1M/KSWaabzBXs490MWcOLnBc+pJv6a+n/OjbMr8oAP1A/EI7B5IK7A6dmoPFWqiZnTWdSHiyOxdtYuCP4aADx7SEANAuZDE+f0mv2Z5VPP++/ivJqtoQHm3pmf6mmaUw5GBlr7IBe0zw7Xzmwcg+nvCJ3gpiCwtpRSfyg5JL/vLWyGHNa7Itsxcf/f6SbClu2dB6Gk7MpTeybjSJB9BIelgXUeFG1Og/OKeFZArSjJAaStcWW/7RT/+Mn0IHI7YMUDRRE5uh6Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwlhUxPbeXZS8WSEaR2BmgoUXddio7QQ3SZOTYaJOkatcQvvJk3f3Al7KsXM835ASuUGFTwZrit8cfj8ql+FDsAQ=="
}
]
},
{
"header": {
"sequence": 6,
"previousBlockHash": "937DDDEF0F9E16BEE53597F8740BC39C402797BD9A500497C2DB7F6B5CB846FA",
"noteCommitment": {
"type": "Buffer",
"data": "base64:q4ND/h5PfCWsWQR3iXw9wj9C++rhs7h8GRTRdhW9dBU="
},
"transactionCommitment": {
"type": "Buffer",
"data": "base64:spq09AfpwAC9c4rcJDlK9iIYCt1jIgDuJSN4MIdIhp8="
},
"target": "9673947260796457140405632176634610505811572608029621013470979893934641",
"randomness": "0",
"timestamp": 1733958145689,
"graffiti": "0000000000000000000000000000000000000000000000000000000000000000",
"noteSize": 9,
"work": "0"
},
"transactions": [
{
"type": "Buffer",
"data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA/mwn/GeBShTNgQCvb481LeNPhzOhNahNWiiwzQdvY9GMhB5SP2LYUgqD2vVd4D9kcHucgzTH9OB83yw1RSLAUAwO6r8pT5m170wJDHcAiJKmfhpbv6w4a6Gt2yhVm3esuqorZvrRHkl9TmjbBLyZcq/iPVJHWwta0pxuFNlQNsYEPW45MnWxzZTn4Jw1AzOspxJjoTT/mpEacN+C/xwLVP1HyiBeQKNvlN4nAB4ilNWWJJj8B9cnXH9VuwO0w+Ernj9Qt2BM7GbkblMrFICf9pWErc1vUuy4uwGy+g4107py0zHoTMEn1jRaVS5DWlcga3huHSC4yC9c863xsV6vNhUmT+0HDp7ZaZf0XnHI5bu1w8nbHOk4IQlsBuzaQd9l3e1M+fgJyc93N9UaWU1ME1Gp7sJcpPBBX5jM6iuwKEGia995AvV5ATgAtdEYMeqNEFokrJH5u7OgzToZiYbTatIIQmTmIfqSZyV2tndXLKxOI5Djfc4ng3Eo4NJn8MuYFpqn/gZbc0evCXZZvUdM7EkvWeSlDlwsbx0OWvTSKiY0wGQhZO7hxfxXeAB0yIG6+mwgV9wcwqWDuoiSlFd3QQjmmmBtoJkXG11/gPLDG/kNwutNyq+te0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwRXbDRfZAvcUJ44/XytkEsTG8OepCvR8Btjm78f/3K960RGQpuz6vy/kYYUopH+a3o14heKtTTADQS4Lqvvr5Aw=="
}
]
}
]
}
30 changes: 30 additions & 0 deletions ironfish/src/rpc/routes/wallet/getAccountTransactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,36 @@ describe('Route wallet/getAccountTransactions', () => {
expect(accountTransactionHashes).toEqual(blockTransactionHashes)
})

it('streams back transactions for a given block sequence range', async () => {
const node = routeTest.node
const account = await useAccountFixture(node.wallet, 'sequence-range')

const block1 = await useMinerBlockFixture(routeTest.chain, undefined, account, node.wallet)
await expect(node.chain).toAddBlock(block1)
const block2 = await useMinerBlockFixture(routeTest.chain, undefined, account, node.wallet)
await expect(node.chain).toAddBlock(block2)
const block3 = await useMinerBlockFixture(routeTest.chain, undefined, account, node.wallet)
await expect(node.chain).toAddBlock(block3)
await node.wallet.scan()

const response = routeTest.client.wallet.getAccountTransactionsStream({
account: account.name,
startSequence: block2.header.sequence,
endSequence: block3.header.sequence,
})

const blockTransactionHashes = [
block2.transactions[0].hash(),
block3.transactions[0].hash(),
]
const accountTransactions = await AsyncUtils.materialize(response.contentStream())
const accountTransactionHashes = accountTransactions
.map(({ hash }) => Buffer.from(hash, 'hex'))
.sort()

expect(accountTransactionHashes).toEqual(blockTransactionHashes)
})

it('streams back all transactions by default', async () => {
const node = routeTest.node
const account = await useAccountFixture(node.wallet, 'default-stream')
Expand Down
18 changes: 15 additions & 3 deletions ironfish/src/rpc/routes/wallet/getAccountTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type GetAccountTransactionsRequest = {
account?: string
hash?: string
sequence?: number
startSequence?: number
endSequence?: number
limit?: number
offset?: number
reverse?: boolean
Expand All @@ -34,6 +36,8 @@ export const GetAccountTransactionsRequestSchema: yup.ObjectSchema<GetAccountTra
account: yup.string().trim(),
hash: yup.string().notRequired(),
sequence: yup.number().min(GENESIS_BLOCK_SEQUENCE).notRequired(),
startSequence: yup.number().min(GENESIS_BLOCK_SEQUENCE).notRequired(),
endSequence: yup.number().min(GENESIS_BLOCK_SEQUENCE).notRequired(),
limit: yup.number().notRequired(),
offset: yup.number().notRequired(),
reverse: yup.boolean().notRequired().default(true),
Expand Down Expand Up @@ -86,9 +90,17 @@ routes.register<typeof GetAccountTransactionsRequestSchema, GetAccountTransactio
let count = 0
let offset = 0

const transactions = request.data.sequence
? account.getTransactionsBySequence(request.data.sequence)
: account.getTransactionsByTime(undefined, { reverse: request.data.reverse })
let transactions
if (request.data.startSequence || request.data.endSequence) {
transactions = account.getTransactionsBySequenceRange(
request.data.startSequence,
request.data.endSequence,
)
} else if (request.data.sequence) {
transactions = account.getTransactionsBySequence(request.data.sequence)
Copy link
Contributor

@NullSoldier NullSoldier Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing we can just delete this in the future assuming getTransactionsBySequenceRange is inclusive which it looks like it is. Don't do this in this PR, it's just a thought when we start deprecating code in the RPC layer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is inclusive, so we can delete getTransactionsBySequence

} else {
transactions = account.getTransactionsByTime(undefined, { reverse: request.data.reverse })
}

for await (const transaction of transactions) {
if (request.closed) {
Expand Down
16 changes: 16 additions & 0 deletions ironfish/src/wallet/account/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,22 @@ export class Account {
}
}

async *getTransactionsBySequenceRange(
startSequence?: number,
endSequence?: number,
tx?: IDatabaseTransaction,
): AsyncGenerator<Readonly<TransactionValue>> {
startSequence = startSequence ?? GENESIS_BLOCK_SEQUENCE
endSequence = endSequence ?? 2 ** 32 - 1

for await (const {
hash: _hash,
...transaction
} of this.walletDb.loadTransactionsInSequenceRange(this, startSequence, endSequence, tx)) {
yield transaction
}
}

getPendingTransactions(
headSequence: number,
tx?: IDatabaseTransaction,
Expand Down