|
1 | 1 | import stringify from '@agoric/swingset-vat/src/kernel/json-stable-stringify';
|
| 2 | +import { |
| 3 | + importMailbox, |
| 4 | + exportMailbox, |
| 5 | +} from '@agoric/swingset-vat/src/devices/mailbox'; |
2 | 6 |
|
3 | 7 | import { launch } from './launch-chain';
|
4 | 8 | import makeBlockManager from './block-manager';
|
5 | 9 |
|
6 | 10 | const AG_COSMOS_INIT = 'AG_COSMOS_INIT';
|
7 | 11 |
|
| 12 | +const makeChainStorage = (call, prefix = '', imp = x => x, exp = x => x) => { |
| 13 | + let cache = new Map(); |
| 14 | + let changedKeys = new Set(); |
| 15 | + const storage = { |
| 16 | + has(key) { |
| 17 | + // It's more efficient just to get the value. |
| 18 | + const val = storage.get(key); |
| 19 | + return !!val; |
| 20 | + }, |
| 21 | + set(key, obj) { |
| 22 | + if (cache.get(key) !== obj) { |
| 23 | + cache.set(key, obj); |
| 24 | + changedKeys.add(key); |
| 25 | + } |
| 26 | + }, |
| 27 | + get(key) { |
| 28 | + if (cache.has(key)) { |
| 29 | + // Our cache has the value. |
| 30 | + return cache.get(key); |
| 31 | + } |
| 32 | + const retStr = call(stringify({ method: 'get', key: `${prefix}${key}` })); |
| 33 | + const ret = JSON.parse(retStr); |
| 34 | + const value = ret && JSON.parse(ret); |
| 35 | + // console.log(` value=${value}`); |
| 36 | + const obj = value && imp(value); |
| 37 | + cache.set(key, obj); |
| 38 | + // We need to add this in case the caller mutates the state, as in |
| 39 | + // mailbox.js, which mutates on basically every get. |
| 40 | + changedKeys.add(key); |
| 41 | + return obj; |
| 42 | + }, |
| 43 | + commit() { |
| 44 | + for (const key of changedKeys.keys()) { |
| 45 | + const obj = cache.get(key); |
| 46 | + const value = stringify(exp(obj)); |
| 47 | + call( |
| 48 | + stringify({ |
| 49 | + method: 'set', |
| 50 | + key: `${prefix}${key}`, |
| 51 | + value, |
| 52 | + }), |
| 53 | + ); |
| 54 | + } |
| 55 | + // Reset our state. |
| 56 | + storage.abort(); |
| 57 | + }, |
| 58 | + abort() { |
| 59 | + // Just reset our state. |
| 60 | + cache = new Map(); |
| 61 | + changedKeys = new Set(); |
| 62 | + }, |
| 63 | + }; |
| 64 | + return storage; |
| 65 | +}; |
| 66 | + |
8 | 67 | export default async function main(progname, args, { path, env, agcc }) {
|
9 | 68 | const portNums = {};
|
10 | 69 |
|
@@ -118,49 +177,13 @@ export default async function main(progname, args, { path, env, agcc }) {
|
118 | 177 | // so the 'externalStorage' object can close over the single mutable
|
119 | 178 | // instance, and we update the 'portNums.storage' value each time toSwingSet is called
|
120 | 179 | async function launchAndInitializeSwingSet() {
|
121 |
| - // this object is used to store the mailbox state. we only ever use |
122 |
| - // key='mailbox' |
123 |
| - const mailboxStorage = { |
124 |
| - has(key) { |
125 |
| - // x/swingset/storage.go returns "true" or "false" |
126 |
| - const retStr = chainSend( |
127 |
| - portNums.storage, |
128 |
| - stringify({ method: 'has', key }), |
129 |
| - ); |
130 |
| - const ret = JSON.parse(retStr); |
131 |
| - if (Boolean(ret) !== ret) { |
132 |
| - throw new Error(`chainSend(has) returned ${ret} not Boolean`); |
133 |
| - } |
134 |
| - return ret; |
135 |
| - }, |
136 |
| - set(key, value) { |
137 |
| - if (value !== `${value}`) { |
138 |
| - throw new Error( |
139 |
| - `golang storage API only takes string values, not '${JSON.stringify( |
140 |
| - value, |
141 |
| - )}'`, |
142 |
| - ); |
143 |
| - } |
144 |
| - const encodedValue = stringify(value); |
145 |
| - chainSend( |
146 |
| - portNums.storage, |
147 |
| - stringify({ method: 'set', key, value: encodedValue }), |
148 |
| - ); |
149 |
| - }, |
150 |
| - get(key) { |
151 |
| - const retStr = chainSend( |
152 |
| - portNums.storage, |
153 |
| - stringify({ method: 'get', key }), |
154 |
| - ); |
155 |
| - // console.log(`s.get(${key}) retstr=${retstr}`); |
156 |
| - const encodedValue = JSON.parse(retStr); |
157 |
| - // console.log(` encodedValue=${encodedValue}`); |
158 |
| - const value = JSON.parse(encodedValue); |
159 |
| - // console.log(` value=${value}`); |
160 |
| - return value; |
161 |
| - }, |
162 |
| - }; |
163 |
| - |
| 180 | + // this object is used to store the mailbox state. |
| 181 | + const mailboxStorage = makeChainStorage( |
| 182 | + msg => chainSend(portNums.storage, msg), |
| 183 | + 'mailbox.', |
| 184 | + importMailbox, |
| 185 | + exportMailbox, |
| 186 | + ); |
164 | 187 | function doOutboundBridge(dstID, obj) {
|
165 | 188 | const portNum = portNums[dstID];
|
166 | 189 | if (portNum === undefined) {
|
|
0 commit comments