Skip to content

Commit 0c44416

Browse files
committed
rpc: enrich tx/prepare response with MSB preimage + fix mbs field (tests/docs)
1 parent 65ba158 commit 0c44416

3 files changed

Lines changed: 77 additions & 11 deletions

File tree

APP_DEV.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ curl -s -X POST http://127.0.0.1:5001/v1/contract/tx/prepare \
181181

182182
The response contains:
183183
- `tx` (hex32): the exact 32-byte tx hash that must be signed
184-
- `command_hash` (hex32): hash of the prepared command (used by MSB payload)
184+
- `prepared_command` (object): echo of the typed command `{ type, value }` (what the wallet should display)
185+
- `command_hash` (hex32): hash of the canonical JSON of `prepared_command`
186+
- `msb` (object): the MSB tx preimage fields the `tx` commits to (`networkId`, `txv`, `iw`, `ch`, `bs`, `mbs`, `in`, `operationType`)
185187

186188
### Step D — Sign locally in the wallet
187189

@@ -222,11 +224,18 @@ curl -s -X POST http://127.0.0.1:5001/v1/contract/tx \
222224

223225
### Step G — Read app state
224226

225-
Apps typically write under `app/...`. Read via:
227+
Apps typically write under `app/...` (app-defined). Read via:
228+
229+
```sh
230+
curl -s 'http://127.0.0.1:5001/v1/state?key=<urlencoded-hyperbee-key>&confirmed=false' | jq
231+
```
232+
233+
Example (Tuxemon demo app):
226234

227235
```sh
228236
curl -s 'http://127.0.0.1:5001/v1/state?key=app%tuxedex%2F<wallet-pubkey-hex32>&confirmed=false' | jq
229237
```
238+
```
230239
231240
The `confirmed` flag controls whether you read from:
232241
- the latest local view (`confirmed=false`), or

rpc/services.js

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ const requireApi = (peer) => {
1717
};
1818

1919
export async function getStatus(peer) {
20-
const subnetBootstrapHex = b4a.isBuffer(peer.bootstrap)
21-
? b4a.toString(peer.bootstrap, "hex")
22-
: peer.bootstrap != null
23-
? String(peer.bootstrap)
20+
const subnetBootstrapHex = b4a.isBuffer(peer.config.bootstrap)
21+
? b4a.toString(peer.config.bootstrap, "hex")
22+
: peer.config.bootstrap != null
23+
? String(peer.config.bootstrap)
2424
: null;
2525

2626
const peerMsbAddress = peer.msbClient.pubKeyHexToAddress(peer.wallet.publicKey);
@@ -123,19 +123,67 @@ export async function contractGenerateNonce(peer) {
123123
export async function contractPrepareTx(peer, { prepared_command, address, nonce } = {}) {
124124
const api = requireApi(peer);
125125
if (!isObject(prepared_command)) throw new Error("prepared_command must be an object.");
126+
if (typeof prepared_command.type !== "string" || prepared_command.type.length < 1) {
127+
throw new Error("prepared_command.type must be a non-empty string.");
128+
}
129+
if (prepared_command.value === undefined) {
130+
throw new Error("prepared_command.value is missing.");
131+
}
126132
const addr = asHex32(address, "address");
127133
const n = asHex32(nonce, "nonce");
128134

129135
if (peer?.protocol.instance?.safeJsonStringify == null) {
130136
throw new Error("safeJsonStringify is not available on protocol instance.");
131137
}
132138

133-
const json = peer.protocol.instance.safeJsonStringify(prepared_command);
134-
if (json == null) throw new Error("Failed to stringify prepared_command.");
139+
const prepared_json = peer.protocol.instance.safeJsonStringify(prepared_command);
140+
if (prepared_json == null) throw new Error("Failed to stringify prepared_command.");
141+
142+
const command_hash = await createHash(prepared_json);
143+
144+
const networkId = peer.msbClient.networkId;
145+
const msbBootstrap = peer.msbClient.bootstrapHex;
146+
const txv = await peer.msbClient.getTxvHex();
147+
const subnetBootstrap =
148+
b4a.isBuffer(peer.config.bootstrap)
149+
? b4a.toString(peer.config.bootstrap, "hex")
150+
: peer.config.bootstrap != null
151+
? String(peer.config.bootstrap)
152+
: null;
153+
154+
const incomingWritingKey = peer.writerLocalKey ?? api.getPeerWriterKey?.();
155+
if (!incomingWritingKey || !/^[0-9a-f]{64}$/i.test(String(incomingWritingKey))) {
156+
throw new Error("Peer writer key is not available.");
157+
}
158+
if (!subnetBootstrap || !/^[0-9a-f]{64}$/i.test(String(subnetBootstrap))) {
159+
throw new Error("Peer subnet bootstrap is not available.");
160+
}
161+
162+
const tx = await peer.protocol.instance.generateTx(
163+
networkId,
164+
txv,
165+
String(incomingWritingKey).toLowerCase(),
166+
command_hash,
167+
String(subnetBootstrap).toLowerCase(),
168+
String(msbBootstrap).toLowerCase(),
169+
n
170+
);
135171

136-
const command_hash = await createHash(json);
137-
const tx = await api.generateTx(addr, command_hash, n);
138-
return { tx, command_hash };
172+
return {
173+
tx,
174+
prepared_command,
175+
command_hash,
176+
msb: {
177+
networkId,
178+
txv,
179+
iw: String(incomingWritingKey).toLowerCase(),
180+
ch: command_hash,
181+
bs: String(subnetBootstrap).toLowerCase(),
182+
mbs: String(msbBootstrap).toLowerCase(),
183+
in: n,
184+
operationType: 12,
185+
},
186+
};
139187
}
140188

141189
export async function contractTx(peer, { tx, prepared_command, address, signature, nonce, sim = false } = {}) {

tests/acceptance/rpc.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ test("rpc: wallet-signed tx simulate via prepare+sign+broadcast", async (t) => {
288288
});
289289
t.is(prep.status, 200);
290290
const tx = prep.json?.tx;
291+
t.is(prep.json?.command_hash, prep.json?.msb?.ch);
292+
t.is(prep.json?.msb?.in, nonce);
293+
t.is(prep.json?.msb?.operationType, 12);
294+
t.is(typeof prep.json?.msb?.networkId, "number");
295+
t.is(typeof prep.json?.msb?.txv, "string");
296+
t.is(typeof prep.json?.msb?.iw, "string");
297+
t.is(typeof prep.json?.msb?.bs, "string");
298+
t.is(typeof prep.json?.msb?.mbs, "string");
299+
t.is(prep.json?.prepared_command?.type, prepared_command.type);
291300

292301
const signature = externalWallet.sign(b4a.from(tx, "hex"));
293302
const simRes = await httpJson("POST", `${baseUrl}/v1/contract/tx`, {

0 commit comments

Comments
 (0)