-
Notifications
You must be signed in to change notification settings - Fork 206
/
fake-chain.js
135 lines (116 loc) · 3.86 KB
/
fake-chain.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* eslint-disable no-await-in-loop */
import path from 'path';
import fs from 'fs';
import stringify from '@agoric/swingset-vat/src/kernel/json-stable-stringify';
import anylogger from 'anylogger';
import { launch } from '../launch-chain';
import makeBlockManager from '../block-manager';
import { makeWithQueue } from './vats/queue';
const log = anylogger('fake-chain');
const PRETEND_BLOCK_DELAY = 5;
const scaleBlockTime = ms => Math.floor(ms / 1000);
async function readMap(file) {
let content;
const map = new Map();
try {
content = await fs.promises.readFile(file);
} catch (e) {
return map;
}
const obj = JSON.parse(content);
Object.entries(obj).forEach(([k, v]) => map.set(k, v));
return map;
}
async function writeMap(file, map) {
const obj = {};
[...map.entries()].forEach(([k, v]) => (obj[k] = v));
const json = stringify(obj);
await fs.promises.writeFile(file, json);
}
export async function connectToFakeChain(basedir, GCI, role, delay, inbound) {
const mailboxFile = path.join(basedir, `fake-chain-${GCI}-mailbox.json`);
const bootAddress = `${GCI}-client`;
const mailboxStorage = await readMap(mailboxFile);
const vatsdir = path.join(basedir, 'vats');
const argv = [
`--role=${role}`,
`--give-me-all-the-agoric-powers`,
bootAddress,
];
const stateDBdir = path.join(basedir, `fake-chain-${GCI}-state`);
function doOutboundBridge(dstID, _obj) {
// console.error('received', dstID, obj);
return `Bridge device (${dstID}) not implemented for fake-chain`;
}
function flushChainSends(replay) {
if (replay) {
throw Error(`Replay not implemented`);
}
}
const s = await launch(
stateDBdir,
mailboxStorage,
doOutboundBridge,
flushChainSends,
vatsdir,
argv,
);
const blockManager = makeBlockManager(s);
const { savedHeight, savedActions } = s;
let blockHeight = savedHeight;
let blockTime =
savedActions.length > 0
? savedActions[0].blockTime
: scaleBlockTime(Date.now());
let intoChain = [];
let thisBlock = [];
let nextBlockTimeout = 0;
const maximumDelay = (delay || PRETEND_BLOCK_DELAY) * 1000;
const withBlockQueue = makeWithQueue();
const simulateBlock = withBlockQueue(async function unqueuedSimulateBlock() {
const actualStart = Date.now();
// Gather up the new messages into the latest block.
thisBlock.push(...intoChain);
intoChain = [];
try {
blockTime += PRETEND_BLOCK_DELAY;
blockHeight += 1;
await blockManager({ type: 'BEGIN_BLOCK', blockHeight, blockTime });
for (let i = 0; i < thisBlock.length; i += 1) {
const [newMessages, acknum] = thisBlock[i];
await blockManager({
type: 'DELIVER_INBOUND',
peer: bootAddress,
messages: newMessages,
ack: acknum,
blockHeight,
blockTime,
});
}
await blockManager({ type: 'END_BLOCK', blockHeight, blockTime });
// Done processing, "commit the block".
await blockManager({ type: 'COMMIT_BLOCK', blockHeight, blockTime });
await writeMap(mailboxFile, mailboxStorage);
thisBlock = [];
blockTime += scaleBlockTime(Date.now() - actualStart);
} catch (e) {
log.error(`error fake processing`, e);
}
nextBlockTimeout = setTimeout(simulateBlock, maximumDelay);
// TODO: maybe add latency to the inbound messages.
const mailboxJSON = mailboxStorage.get(`mailbox.${bootAddress}`);
const mailbox = mailboxJSON && JSON.parse(mailboxJSON);
const { outbox = [], ack = 0 } = mailbox || {};
inbound(GCI, outbox, ack);
});
async function deliver(newMessages, acknum) {
intoChain.push([newMessages, acknum]);
if (!delay) {
clearTimeout(nextBlockTimeout);
await simulateBlock();
}
}
// Start the first pretend block.
nextBlockTimeout = setTimeout(simulateBlock, maximumDelay);
return deliver;
}