tigerbeetle-node 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -69
- package/dist/benchmark.js +96 -94
- package/dist/benchmark.js.map +1 -1
- package/dist/index.d.ts +82 -82
- package/dist/index.js +74 -93
- package/dist/index.js.map +1 -1
- package/dist/test.js +134 -111
- package/dist/test.js.map +1 -1
- package/package.json +3 -2
- package/src/benchmark.ts +114 -118
- package/src/index.ts +102 -111
- package/src/node.zig +52 -50
- package/src/test.ts +146 -125
- package/src/tigerbeetle/scripts/benchmark.sh +5 -0
- package/src/tigerbeetle/scripts/install_zig.sh +2 -2
- package/src/tigerbeetle/src/benchmark.zig +63 -96
- package/src/tigerbeetle/src/config.zig +6 -6
- package/src/tigerbeetle/src/demo.zig +0 -13
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +10 -10
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +3 -1
- package/src/tigerbeetle/src/{demo_04_create_transfers_two_phase_commit.zig → demo_04_create_pending_transfers.zig} +12 -6
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +37 -0
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +24 -0
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +1 -1
- package/src/tigerbeetle/src/io/linux.zig +4 -4
- package/src/tigerbeetle/src/main.zig +1 -1
- package/src/tigerbeetle/src/message_pool.zig +1 -1
- package/src/tigerbeetle/src/state_machine.zig +1804 -797
- package/src/tigerbeetle/src/tigerbeetle.zig +103 -98
- package/src/tigerbeetle/src/vsr/replica.zig +6 -6
- package/src/translate.zig +10 -0
- package/src/tigerbeetle/src/demo_05_accept_transfers.zig +0 -23
- package/src/tigerbeetle/src/demo_06_reject_transfers.zig +0 -17
- package/src/tigerbeetle/src/format_test.zig +0 -69
package/README.md
CHANGED
|
@@ -9,27 +9,49 @@ The following steps will install the `tigerbeetle-node` module to your current w
|
|
|
9
9
|
* NodeJS >= `14.0.0`. _(If the correct version is not installed, an installation error will occur)_
|
|
10
10
|
|
|
11
11
|
> Your operating system should be Linux (kernel >= v5.6) or macOS. Windows support is not yet available but is in the works.
|
|
12
|
-
|
|
13
|
-
### YARN Package Manager
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
yarn add
|
|
13
|
+
### YARN Package Manager Installation
|
|
14
|
+
```shell
|
|
15
|
+
yarn add tigerbeetle-node
|
|
18
16
|
```
|
|
19
17
|
or
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```sh
|
|
18
|
+
### NPM Package Manager Installation
|
|
19
|
+
```shell
|
|
23
20
|
npm install tigerbeetle-node
|
|
24
21
|
```
|
|
25
22
|
|
|
26
23
|
**Development**
|
|
27
24
|
|
|
28
25
|
Follow these steps to get up and running when cloning the repo:
|
|
29
|
-
|
|
30
|
-
```sh
|
|
26
|
+
```shell
|
|
31
27
|
git clone --recurse-submodules https://github.com/coilhq/tigerbeetle-node.git
|
|
32
|
-
|
|
28
|
+
cd tigerbeetle-node/
|
|
29
|
+
yarn install --immutable
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Build locally using `yarn`:
|
|
33
|
+
```shell
|
|
34
|
+
# Run the following from this directory:
|
|
35
|
+
yarn && yarn build
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
* **Please note: `yarn clean` will remove Zig and NodeAPI C headers, which mean you need to run:**
|
|
39
|
+
```shell
|
|
40
|
+
./scripts/postinstall.sh #Install Zig and NodeJS C Headers
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
***Yarn - Run Test***
|
|
44
|
+
Ensure TigerBeetle (`init` & `start`) is running on the port configured in `test.ts`, then run:
|
|
45
|
+
```shell
|
|
46
|
+
./tigerbeetle init --cluster=1 --replica=0 --directory=.
|
|
47
|
+
./tigerbeetle start --cluster=1 --replica=0 --directory=. --addresses=3001
|
|
48
|
+
yarn test
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
***Yarn - Run Benchmark***
|
|
52
|
+
Run the benchmark (The `benchmark` will automatically start TigerBeetle on port `3001` _(single replica)_:
|
|
53
|
+
```shell
|
|
54
|
+
yarn benchmark
|
|
33
55
|
```
|
|
34
56
|
|
|
35
57
|
## Usage
|
|
@@ -41,7 +63,7 @@ Future releases will allow multiple client instantiations.
|
|
|
41
63
|
import { createClient } from 'tigerbeetle-node'
|
|
42
64
|
|
|
43
65
|
const client = createClient({
|
|
44
|
-
cluster_id:
|
|
66
|
+
cluster_id: 0,
|
|
45
67
|
replica_addresses: ['3001', '3002', '3003']
|
|
46
68
|
})
|
|
47
69
|
```
|
|
@@ -54,15 +76,15 @@ This is reflected in the below function interfaces where each one takes in an ar
|
|
|
54
76
|
```js
|
|
55
77
|
const account = {
|
|
56
78
|
id: 137n, // u128
|
|
57
|
-
user_data: 0n, // u128, opaque third-party identifier to link this account
|
|
79
|
+
user_data: 0n, // u128, opaque third-party identifier to link this account to an external entity:
|
|
58
80
|
reserved: Buffer.alloc(48, 0), // [48]u8
|
|
59
|
-
|
|
81
|
+
ledger: 1, // u32, ledger value
|
|
60
82
|
code: 718, // u16, a chart of accounts code describing the type of account (e.g. clearing, settlement)
|
|
61
|
-
flags: 0, //
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
flags: 0, // u16
|
|
84
|
+
debits_pending: 0n, // u64
|
|
85
|
+
debits_posted: 0n, // u64
|
|
86
|
+
credits_pending: 0n, // u64
|
|
87
|
+
credits_posted: 0n, // u64
|
|
66
88
|
timestamp: 0n, // u64, Reserved: This will be set by the server.
|
|
67
89
|
}
|
|
68
90
|
|
|
@@ -87,7 +109,7 @@ The `flags` on an account provide a way for you to enforce policies by toggling
|
|
|
87
109
|
|----------|----------------------------------|-----------------------------------------|
|
|
88
110
|
| `linked` | `debits_must_not_exceed_credits` | `credits_must_not_exceed_debits` |
|
|
89
111
|
|
|
90
|
-
The creation of an account can be linked to the successful creation of another by setting the `linked` flag (see [linked events](#linked-events)). By setting `debits_must_not_exceed_credits`, then any transfer such that `
|
|
112
|
+
The creation of an account can be linked to the successful creation of another by setting the `linked` flag (see [linked events](#linked-events)). By setting `debits_must_not_exceed_credits`, then any transfer such that `debits_posted + debits_pending + amount > credits_posted` will fail. Similarly for `credits_must_not_exceed_debits`.
|
|
91
113
|
```js
|
|
92
114
|
enum CreateAccountFlags {
|
|
93
115
|
linked = (1 << 0),
|
|
@@ -111,13 +133,13 @@ The `id` of the account is used for lookups. Only matched accounts are returned.
|
|
|
111
133
|
* id: 137n,
|
|
112
134
|
* user_data: 0n,
|
|
113
135
|
* reserved: Buffer,
|
|
114
|
-
*
|
|
136
|
+
* ledger: 1,
|
|
115
137
|
* code: 718,
|
|
116
138
|
* flags: 0,
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
139
|
+
* debits_pending: 0n,
|
|
140
|
+
* debits_posted: 0n,
|
|
141
|
+
* credits_pending: 0n,
|
|
142
|
+
* credits_posted: 0n,
|
|
121
143
|
* timestamp: 1623062009212508993n,
|
|
122
144
|
* }]
|
|
123
145
|
*/
|
|
@@ -129,59 +151,57 @@ This creates a journal entry between two accounts.
|
|
|
129
151
|
```js
|
|
130
152
|
const transfer = {
|
|
131
153
|
id: 1n, // u128
|
|
154
|
+
// Double-entry accounting:
|
|
132
155
|
debit_account_id: 1n, // u128
|
|
133
156
|
credit_account_id: 2n, // u128
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
// Opaque third-party identifier to link this transfer to an external entity:
|
|
158
|
+
user_data: 0n, // u128
|
|
159
|
+
reserved: 0n, // u128
|
|
160
|
+
// Timeout applicable for a pending/2-phase transfer:
|
|
161
|
+
timeout: 0n, // u64, in nano-seconds.
|
|
162
|
+
// Collection of accounts usually grouped by the currency:
|
|
163
|
+
// You can't transfer money between accounts with different ledgers:
|
|
164
|
+
ledger: 720, // u32, ledger for transfer (e.g. currency).
|
|
165
|
+
// Chart of accounts code describing the reason for the transfer:
|
|
166
|
+
code: 1, // u16, (e.g. deposit, settlement)
|
|
167
|
+
flags: 0, // u16
|
|
139
168
|
amount: 10n, // u64
|
|
140
169
|
timestamp: 0n, //u64, Reserved: This will be set by the server.
|
|
141
170
|
}
|
|
142
|
-
|
|
143
171
|
const errors = await client.createTransfers([transfer])
|
|
144
172
|
```
|
|
145
|
-
Two-phase transfers are supported natively by toggling the appropriate flag. TigerBeetle will then adjust the `
|
|
146
|
-
| bit 0 | bit 1 | bit 2 |
|
|
147
|
-
|----------|--------------------|------------------|
|
|
148
|
-
| `linked` | `posting` | `condition` |
|
|
173
|
+
Two-phase transfers are supported natively by toggling the appropriate flag. TigerBeetle will then adjust the `credits_pending` and `debits_pending` fields of the appropriate accounts. A corresponding commit transfer then needs to be sent to accept or reject the transfer.
|
|
149
174
|
|
|
150
|
-
|
|
175
|
+
Transfers within a batch may also be linked (see [linked events](#linked-events)).
|
|
151
176
|
```js
|
|
152
|
-
enum
|
|
153
|
-
linked = (1 << 0
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
enum TransferFlags {
|
|
178
|
+
linked = (1 << 0),
|
|
179
|
+
pending = (1 << 1),
|
|
180
|
+
post_pending_transfer = (1 << 2),
|
|
181
|
+
void_pending_transfer = (1 << 3)
|
|
156
182
|
}
|
|
157
|
-
|
|
158
|
-
//
|
|
183
|
+
|
|
184
|
+
// Two-phase transfer (pending):
|
|
159
185
|
let flags = 0n
|
|
160
|
-
flags |= TransferFlags.
|
|
186
|
+
flags |= TransferFlags.pending
|
|
161
187
|
|
|
162
|
-
// two-phase transfer
|
|
188
|
+
// Linked two-phase transfer (pending):
|
|
163
189
|
let flags = 0n
|
|
164
|
-
flags |= TransferFlags.
|
|
165
|
-
flags |= TransferFlags.
|
|
190
|
+
flags |= TransferFlags.linked
|
|
191
|
+
flags |= TransferFlags.pending
|
|
166
192
|
```
|
|
167
193
|
|
|
168
|
-
###
|
|
169
|
-
|
|
170
|
-
This is used to commit a two-phase transfer.
|
|
171
|
-
| bit 0 | bit 1 | bit 2 |
|
|
172
|
-
|----------|----------|------------|
|
|
173
|
-
| `linked` | `reject` | `preimage` |
|
|
194
|
+
### Post a Pending transfer (2-phase)
|
|
174
195
|
|
|
175
|
-
|
|
196
|
+
With `flags = post_pending_transfer`, TigerBeetle will accept the transfer. TigerBeetle will atomically rollback the changes to `debits_pending` and `credits_pending` of the appropriate accounts and apply them to the `debits_posted` and `credits_posted` balances.
|
|
176
197
|
```js
|
|
177
|
-
const
|
|
178
|
-
id:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
flags: 0, // u32
|
|
198
|
+
const post = {
|
|
199
|
+
id: 2n, // u128, must correspond to the transfer id
|
|
200
|
+
pending_id: 1n, // u128, id of the pending transfer
|
|
201
|
+
flags: TransferFlags.post_pending_transfer, // to void, use [void_pending_transfer]
|
|
182
202
|
timestamp: 0n, // u64, Reserved: This will be set by the server.
|
|
183
203
|
}
|
|
184
|
-
const errors = await client.
|
|
204
|
+
const errors = await client.createTransfers([post])
|
|
185
205
|
```
|
|
186
206
|
|
|
187
207
|
### Linked events
|
|
@@ -193,10 +213,10 @@ let batch = []
|
|
|
193
213
|
let linkedFlag = 0
|
|
194
214
|
linkedFlag |= CreateTransferFlags.linked
|
|
195
215
|
|
|
196
|
-
// An individual transfer (successful)
|
|
216
|
+
// An individual transfer (successful):
|
|
197
217
|
batch.push({ id: 1n, ... })
|
|
198
218
|
|
|
199
|
-
// A chain of 4 transfers (the last transfer in the chain closes the chain with linked=false)
|
|
219
|
+
// A chain of 4 transfers (the last transfer in the chain closes the chain with linked=false):
|
|
200
220
|
batch.push({ id: 2n, ..., flags: linkedFlag }) // Commit/rollback.
|
|
201
221
|
batch.push({ id: 3n, ..., flags: linkedFlag }) // Commit/rollback.
|
|
202
222
|
batch.push({ id: 2n, ..., flags: linkedFlag }) // Fail with exists
|
|
@@ -206,11 +226,11 @@ batch.push({ id: 4n, ..., flags: 0 }) // Fail without committing.
|
|
|
206
226
|
// This should not see any effect from the failed chain above.
|
|
207
227
|
batch.push({ id: 2n, ..., flags: 0 })
|
|
208
228
|
|
|
209
|
-
// A chain of 2 transfers (the first transfer fails the chain)
|
|
229
|
+
// A chain of 2 transfers (the first transfer fails the chain):
|
|
210
230
|
batch.push({ id: 2n, ..., flags: linkedFlag })
|
|
211
231
|
batch.push({ id: 3n, ..., flags: 0 })
|
|
212
232
|
|
|
213
|
-
// A chain of 2 transfers (successful)
|
|
233
|
+
// A chain of 2 transfers (successful):
|
|
214
234
|
batch.push({ id: 3n, ..., flags: linkedFlag })
|
|
215
235
|
batch.push({ id: 4n, ..., flags: 0 })
|
|
216
236
|
|
|
@@ -218,13 +238,13 @@ const errors = await client.createTransfers(batch)
|
|
|
218
238
|
|
|
219
239
|
/**
|
|
220
240
|
* [
|
|
221
|
-
* { index: 1, error: 1 },
|
|
222
|
-
* { index: 2, error: 1 },
|
|
223
|
-
* { index: 3, error:
|
|
224
|
-
* { index: 4, error: 1 },
|
|
241
|
+
* { index: 1, error: 1 }, // linked_event_failed
|
|
242
|
+
* { index: 2, error: 1 }, // linked_event_failed
|
|
243
|
+
* { index: 3, error: 25 }, // exists
|
|
244
|
+
* { index: 4, error: 1 }, // linked_event_failed
|
|
225
245
|
*
|
|
226
|
-
* { index: 6, error:
|
|
227
|
-
* { index: 7, error: 1 },
|
|
246
|
+
* { index: 6, error: 17 }, // exists_with_different_flags
|
|
247
|
+
* { index: 7, error: 1 }, // linked_event_failed
|
|
228
248
|
* ]
|
|
229
249
|
*/
|
|
230
250
|
```
|
package/dist/benchmark.js
CHANGED
|
@@ -5,46 +5,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const assert_1 = __importDefault(require("assert"));
|
|
7
7
|
const _1 = require(".");
|
|
8
|
-
const MAX_TRANSFERS =
|
|
9
|
-
const MAX_REQUEST_BATCH_SIZE =
|
|
10
|
-
const
|
|
8
|
+
const MAX_TRANSFERS = 51200;
|
|
9
|
+
const MAX_REQUEST_BATCH_SIZE = 5120;
|
|
10
|
+
const IS_TWO_PHASE_TRANSFER = false;
|
|
11
11
|
const IS_RAW_REQUEST = false;
|
|
12
|
-
const PREVIOUS_RAW_REQUEST_RESULT =
|
|
13
|
-
const PREVIOUS_RESULT =
|
|
12
|
+
const PREVIOUS_RAW_REQUEST_RESULT = IS_TWO_PHASE_TRANSFER ? 300000 : 620000;
|
|
13
|
+
const PREVIOUS_RESULT = IS_TWO_PHASE_TRANSFER ? 150000 : 310000;
|
|
14
14
|
const PREVIOUS_BENCHMARK = IS_RAW_REQUEST ? PREVIOUS_RAW_REQUEST_RESULT : PREVIOUS_RESULT;
|
|
15
15
|
const TOLERANCE = 10;
|
|
16
16
|
const client = _1.createClient({
|
|
17
|
-
cluster_id:
|
|
17
|
+
cluster_id: 0,
|
|
18
18
|
replica_addresses: ['3001']
|
|
19
19
|
});
|
|
20
20
|
const TRANSFER_SIZE = 128;
|
|
21
|
-
const COMMIT_SIZE = 64;
|
|
22
21
|
const Zeroed48Bytes = Buffer.alloc(48, 0);
|
|
23
|
-
const Zeroed32Bytes = Buffer.alloc(32, 0);
|
|
24
22
|
const accountA = {
|
|
25
23
|
id: 137n,
|
|
26
24
|
user_data: 0n,
|
|
27
25
|
reserved: Zeroed48Bytes,
|
|
28
|
-
|
|
26
|
+
ledger: 1,
|
|
27
|
+
code: 1,
|
|
29
28
|
flags: 0,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
credits_reserved: 0n,
|
|
29
|
+
debits_pending: 0n,
|
|
30
|
+
debits_posted: 0n,
|
|
31
|
+
credits_pending: 0n,
|
|
32
|
+
credits_posted: 0n,
|
|
35
33
|
timestamp: 0n,
|
|
36
34
|
};
|
|
37
35
|
const accountB = {
|
|
38
36
|
id: 138n,
|
|
39
37
|
user_data: 0n,
|
|
40
38
|
reserved: Zeroed48Bytes,
|
|
41
|
-
|
|
39
|
+
ledger: 1,
|
|
40
|
+
code: 1,
|
|
42
41
|
flags: 0,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
credits_reserved: 0n,
|
|
42
|
+
debits_pending: 0n,
|
|
43
|
+
debits_posted: 0n,
|
|
44
|
+
credits_pending: 0n,
|
|
45
|
+
credits_posted: 0n,
|
|
48
46
|
timestamp: 0n,
|
|
49
47
|
};
|
|
50
48
|
const rawCreateTransfers = async (batch) => {
|
|
@@ -63,46 +61,30 @@ const rawCreateTransfers = async (batch) => {
|
|
|
63
61
|
}
|
|
64
62
|
});
|
|
65
63
|
};
|
|
66
|
-
const rawCommitTransfers = async (batch) => {
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const callback = (error, results) => {
|
|
69
|
-
if (error) {
|
|
70
|
-
reject(error);
|
|
71
|
-
}
|
|
72
|
-
resolve(results);
|
|
73
|
-
};
|
|
74
|
-
try {
|
|
75
|
-
client.rawRequest(_1.Operation.COMMIT_TRANSFER, batch, callback);
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
reject(error);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
64
|
const encodeTransfer = (transfer, offset, output) => {
|
|
83
|
-
assert_1.default(offset + TRANSFER_SIZE <= output.length);
|
|
65
|
+
assert_1.default(BigInt((offset + TRANSFER_SIZE)) <= BigInt(output.length), `Transfer ${transfer} exceeds buffer of ${output}!`);
|
|
84
66
|
output.writeBigUInt64LE(transfer.id, offset);
|
|
85
67
|
output.writeBigUInt64LE(transfer.debit_account_id, offset + 16);
|
|
86
68
|
output.writeBigUInt64LE(transfer.credit_account_id, offset + 32);
|
|
69
|
+
output.writeBigUInt64LE(transfer.user_data, offset + 48);
|
|
70
|
+
output.writeBigUInt64LE(transfer.reserved, offset + 64);
|
|
71
|
+
output.writeBigUInt64LE(transfer.pending_id, offset + 80);
|
|
87
72
|
output.writeBigUInt64LE(transfer.timeout, offset + 96);
|
|
88
|
-
output.writeUInt32LE(transfer.
|
|
89
|
-
output.writeUInt32LE(transfer.
|
|
73
|
+
output.writeUInt32LE(transfer.ledger, offset + 104);
|
|
74
|
+
output.writeUInt32LE(transfer.code, offset + 108);
|
|
75
|
+
output.writeUInt32LE(transfer.flags, offset + 110);
|
|
90
76
|
output.writeBigUInt64LE(transfer.amount, offset + 112);
|
|
91
77
|
output.writeBigUInt64LE(transfer.timestamp, offset + 120);
|
|
92
78
|
};
|
|
93
|
-
const
|
|
94
|
-
assert_1.default(offset + COMMIT_SIZE <= output.length);
|
|
95
|
-
output.writeBigUInt64LE(commit.id, offset);
|
|
96
|
-
};
|
|
97
|
-
const runBenchmarkRawReqeust = async () => {
|
|
79
|
+
const runBenchmarkRawRequest = async () => {
|
|
98
80
|
assert_1.default(MAX_TRANSFERS % MAX_REQUEST_BATCH_SIZE === 0, "The raw request benchmark requires MAX_TRANSFERS to be a multiple of MAX_REQUEST_BATCH_SIZE");
|
|
99
|
-
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and
|
|
81
|
+
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`);
|
|
100
82
|
const transfers = [];
|
|
101
|
-
const
|
|
83
|
+
const posts = [];
|
|
102
84
|
let count = 0;
|
|
103
85
|
while (count < MAX_TRANSFERS) {
|
|
104
86
|
const transferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0);
|
|
105
|
-
const
|
|
87
|
+
const postTransferBatch = Buffer.alloc(MAX_REQUEST_BATCH_SIZE * TRANSFER_SIZE, 0);
|
|
106
88
|
for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
|
|
107
89
|
if (count === MAX_TRANSFERS)
|
|
108
90
|
break;
|
|
@@ -111,27 +93,38 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
111
93
|
id: BigInt(count),
|
|
112
94
|
debit_account_id: accountA.id,
|
|
113
95
|
credit_account_id: accountB.id,
|
|
114
|
-
code: 0,
|
|
115
|
-
reserved: Zeroed32Bytes,
|
|
116
96
|
user_data: 0n,
|
|
117
|
-
|
|
97
|
+
reserved: 0n,
|
|
98
|
+
pending_id: 0n,
|
|
99
|
+
timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
|
|
100
|
+
ledger: 1,
|
|
101
|
+
code: 1,
|
|
102
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.pending : 0,
|
|
118
103
|
amount: 1n,
|
|
119
|
-
timeout: IS_TWO_PHASE_COMMIT ? BigInt(2e9) : 0n,
|
|
120
104
|
timestamp: 0n,
|
|
121
105
|
}, i * TRANSFER_SIZE, transferBatch);
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
id: BigInt(count),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
106
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
107
|
+
encodeTransfer({
|
|
108
|
+
id: BigInt((MAX_TRANSFERS + count)),
|
|
109
|
+
debit_account_id: accountA.id,
|
|
110
|
+
credit_account_id: accountB.id,
|
|
111
|
+
user_data: 0n,
|
|
112
|
+
reserved: 0n,
|
|
113
|
+
pending_id: BigInt(count),
|
|
114
|
+
timeout: 0n,
|
|
115
|
+
ledger: 1,
|
|
116
|
+
code: 1,
|
|
117
|
+
flags: _1.TransferFlags.post_pending_transfer,
|
|
118
|
+
amount: 1n,
|
|
128
119
|
timestamp: 0n,
|
|
129
|
-
}, i *
|
|
120
|
+
}, i * TRANSFER_SIZE, postTransferBatch);
|
|
130
121
|
}
|
|
131
122
|
}
|
|
132
123
|
transfers.push(transferBatch);
|
|
133
|
-
if (
|
|
134
|
-
|
|
124
|
+
if (IS_TWO_PHASE_TRANSFER)
|
|
125
|
+
posts.push(postTransferBatch);
|
|
126
|
+
if (count % 100)
|
|
127
|
+
console.log(`${Number((count / MAX_TRANSFERS) * 100).toFixed(1)}%`);
|
|
135
128
|
}
|
|
136
129
|
assert_1.default(count === MAX_TRANSFERS);
|
|
137
130
|
console.log(`starting benchmark. MAX_TRANSFERS=${MAX_TRANSFERS} REQUEST_BATCH_SIZE=${MAX_REQUEST_BATCH_SIZE} NUMBER_OF_BATCHES=${transfers.length}`);
|
|
@@ -140,16 +133,16 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
140
133
|
const start = Date.now();
|
|
141
134
|
for (let i = 0; i < transfers.length; i++) {
|
|
142
135
|
const ms1 = Date.now();
|
|
143
|
-
const
|
|
144
|
-
assert_1.default(
|
|
136
|
+
const transferErrors = await rawCreateTransfers(transfers[i]);
|
|
137
|
+
assert_1.default(transferErrors.length === 0);
|
|
145
138
|
const ms2 = Date.now();
|
|
146
139
|
const createTransferLatency = ms2 - ms1;
|
|
147
140
|
if (createTransferLatency > maxCreateTransfersLatency) {
|
|
148
141
|
maxCreateTransfersLatency = createTransferLatency;
|
|
149
142
|
}
|
|
150
|
-
if (
|
|
151
|
-
const
|
|
152
|
-
assert_1.default(
|
|
143
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
144
|
+
const commitErrors = await rawCreateTransfers(posts[i]);
|
|
145
|
+
assert_1.default(commitErrors.length === 0);
|
|
153
146
|
const ms3 = Date.now();
|
|
154
147
|
const commitTransferLatency = ms3 - ms2;
|
|
155
148
|
if (commitTransferLatency > maxCommitTransfersLatency) {
|
|
@@ -165,42 +158,51 @@ const runBenchmarkRawReqeust = async () => {
|
|
|
165
158
|
};
|
|
166
159
|
};
|
|
167
160
|
const runBenchmark = async () => {
|
|
168
|
-
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and
|
|
161
|
+
console.log(`pre-allocating ${MAX_TRANSFERS} transfers and posts...`);
|
|
169
162
|
const transfers = [];
|
|
170
|
-
const
|
|
163
|
+
const posts = [];
|
|
171
164
|
let count = 0;
|
|
172
165
|
while (count < MAX_TRANSFERS) {
|
|
173
|
-
const
|
|
174
|
-
const
|
|
166
|
+
const pendingBatch = [];
|
|
167
|
+
const postBatch = [];
|
|
175
168
|
for (let i = 0; i < MAX_REQUEST_BATCH_SIZE; i++) {
|
|
176
169
|
if (count === MAX_TRANSFERS)
|
|
177
170
|
break;
|
|
178
171
|
count += 1;
|
|
179
|
-
|
|
172
|
+
pendingBatch.push({
|
|
180
173
|
id: BigInt(count),
|
|
181
174
|
debit_account_id: accountA.id,
|
|
182
175
|
credit_account_id: accountB.id,
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
pending_id: 0n,
|
|
177
|
+
code: 1,
|
|
178
|
+
ledger: 1,
|
|
179
|
+
reserved: 0n,
|
|
185
180
|
user_data: 0n,
|
|
186
|
-
flags:
|
|
181
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.pending : 0,
|
|
187
182
|
amount: 1n,
|
|
188
|
-
timeout:
|
|
183
|
+
timeout: IS_TWO_PHASE_TRANSFER ? BigInt(2e9) : 0n,
|
|
189
184
|
timestamp: 0n,
|
|
190
185
|
});
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
id: BigInt(count),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
186
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
187
|
+
postBatch.push({
|
|
188
|
+
id: BigInt(MAX_TRANSFERS + count),
|
|
189
|
+
debit_account_id: accountA.id,
|
|
190
|
+
credit_account_id: accountB.id,
|
|
191
|
+
pending_id: BigInt(count),
|
|
192
|
+
code: 1,
|
|
193
|
+
ledger: 1,
|
|
194
|
+
reserved: 0n,
|
|
195
|
+
user_data: 0n,
|
|
196
|
+
flags: IS_TWO_PHASE_TRANSFER ? _1.TransferFlags.post_pending_transfer : 0,
|
|
197
|
+
amount: 1n,
|
|
198
|
+
timeout: 0n,
|
|
197
199
|
timestamp: 0n,
|
|
198
200
|
});
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
|
-
transfers.push(
|
|
202
|
-
if (
|
|
203
|
-
|
|
203
|
+
transfers.push(pendingBatch);
|
|
204
|
+
if (IS_TWO_PHASE_TRANSFER)
|
|
205
|
+
posts.push(postBatch);
|
|
204
206
|
}
|
|
205
207
|
assert_1.default(count === MAX_TRANSFERS);
|
|
206
208
|
console.log(`starting benchmark. MAX_TRANSFERS=${MAX_TRANSFERS} REQUEST_BATCH_SIZE=${MAX_REQUEST_BATCH_SIZE} NUMBER_OF_BATCHES=${transfers.length}`);
|
|
@@ -209,16 +211,16 @@ const runBenchmark = async () => {
|
|
|
209
211
|
const start = Date.now();
|
|
210
212
|
for (let i = 0; i < transfers.length; i++) {
|
|
211
213
|
const ms1 = Date.now();
|
|
212
|
-
const
|
|
213
|
-
assert_1.default(
|
|
214
|
+
const transferErrors = await client.createTransfers(transfers[i]);
|
|
215
|
+
assert_1.default(transferErrors.length === 0);
|
|
214
216
|
const ms2 = Date.now();
|
|
215
217
|
const createTransferLatency = ms2 - ms1;
|
|
216
218
|
if (createTransferLatency > maxCreateTransfersLatency) {
|
|
217
219
|
maxCreateTransfersLatency = createTransferLatency;
|
|
218
220
|
}
|
|
219
|
-
if (
|
|
220
|
-
const
|
|
221
|
-
assert_1.default(
|
|
221
|
+
if (IS_TWO_PHASE_TRANSFER) {
|
|
222
|
+
const commitErrors = await client.createTransfers(posts[i]);
|
|
223
|
+
assert_1.default(commitErrors.length === 0);
|
|
222
224
|
const ms3 = Date.now();
|
|
223
225
|
const commitTransferLatency = ms3 - ms2;
|
|
224
226
|
if (commitTransferLatency > maxCommitTransfersLatency) {
|
|
@@ -238,18 +240,18 @@ const main = async () => {
|
|
|
238
240
|
await client.createAccounts([accountA, accountB]);
|
|
239
241
|
const accountResults = await client.lookupAccounts([accountA.id, accountB.id]);
|
|
240
242
|
assert_1.default(accountResults.length === 2);
|
|
241
|
-
assert_1.default(accountResults[0].
|
|
242
|
-
assert_1.default(accountResults[1].
|
|
243
|
-
const benchmark = IS_RAW_REQUEST ? await
|
|
243
|
+
assert_1.default(accountResults[0].debits_posted === 0n);
|
|
244
|
+
assert_1.default(accountResults[1].debits_posted === 0n);
|
|
245
|
+
const benchmark = IS_RAW_REQUEST ? await runBenchmarkRawRequest() : await runBenchmark();
|
|
244
246
|
const accounts = await client.lookupAccounts([accountA.id, accountB.id]);
|
|
245
247
|
const result = Math.floor((1000 * MAX_TRANSFERS) / benchmark.ms);
|
|
246
248
|
console.log("=============================");
|
|
247
|
-
console.log(`${
|
|
249
|
+
console.log(`${IS_TWO_PHASE_TRANSFER ? 'two-phase ' : ''}transfers per second: ${result}`);
|
|
248
250
|
console.log(`create transfers max p100 latency per 10 000 transfers = ${benchmark.maxCreateTransfersLatency}ms`);
|
|
249
251
|
console.log(`commit transfers max p100 latency per 10 000 transfers = ${benchmark.maxCommitTransfersLatency}ms`);
|
|
250
252
|
assert_1.default(accounts.length === 2);
|
|
251
|
-
assert_1.default(accounts[0].
|
|
252
|
-
assert_1.default(accounts[1].
|
|
253
|
+
assert_1.default(accounts[0].debits_posted === BigInt(MAX_TRANSFERS));
|
|
254
|
+
assert_1.default(accounts[1].credits_posted === BigInt(MAX_TRANSFERS));
|
|
253
255
|
if (result < PREVIOUS_BENCHMARK * (100 - TOLERANCE) / 100) {
|
|
254
256
|
console.warn(`There has been a performance regression. Previous benchmark=${PREVIOUS_BENCHMARK}`);
|
|
255
257
|
}
|