Orgchain v1.12: both sides of a deal, and orgs change hands
Deals go both ways now, OpenOrdex's partially signed transaction from either side, on a lot: an item, or an org inside a holding, which its parent sells. Buy makes an offer, the buy order: the buyer signs the whole deal and the holder countersigns. Sell makes an ask, the sell order: the lot's key signs its input alone with SIGHASH_SINGLE|ANYONECANPAY, committing to that input and to the price to the seller and to nothing else, and any node can take it, leading with a 600-sat coin of its own so the lot lands in its output. An org sells cash-free: before its parent lists it or accepts an offer on it, the org's money, gas tank and items go home, so the price is for the org alone, and a listed org is frozen until its ask is taken or withdrawn. Its buyer adopts it with two new lineage/v0 ops, in either order: join, signed by whoever holds the org's inscription, and adopt, signed by the new parent. The org takes the buyer's next index and derives its keys there, and its inscription moves to its new key. Taking an ask adopts at once; after an accepted offer the buyer adopts when it's ready. The seller's tree keeps a row at the old index. Rehearsed on Bitcoin Core regtest: an org sold on an ask, another on an offer and an item on an ask, twelve beats and 104 transactions, and ord tells the same story. The rehearsal caught that a miner can put a join and its adoption in either order within a block, so a move records both halves and each half belongs to both holdings. The sample ends with both sides standing: lineage's offer for the launch kit, and well-known's ask for mailr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H4upF5LVwmPDDqrhdUfnXh
This commit is contained in:
1 parent
4ad75f0970
commit
adca2709f0
20 files changed
+1018
-195
No files matched your search
@@ -1,9 +1,9 @@
|
||||
# Regtest rehearsal
|
||||
|
||||
Lineage is an ordinals metaprotocol (`SPEC.md`). This folder checks that on real Bitcoin Core and real `ord`: the lab's
|
||||
own action code makes the yolopreneur sample, keyrings included, Bitcoin Core (regtest, standardness on) accepts its
|
||||
transactions byte for byte, `ord` indexes the inscriptions, and the same reducer folds ord's view back into the same
|
||||
trees.
|
||||
own action code makes the yolopreneur sample, keyrings, asks, offers and moves included, Bitcoin Core (regtest,
|
||||
standardness on) accepts its transactions byte for byte, `ord` indexes the inscriptions, and the same reducer folds
|
||||
ord's view back into the same trees.
|
||||
|
||||
Regtest is local and private: nothing is downloaded, blocks are mined on demand, and the data folders stay a few MB.
|
||||
Test coins only.
|
||||
@@ -26,16 +26,20 @@ since the lab pays a fixed 500 sats per transaction.
|
||||
## Rehearse, index, compare
|
||||
|
||||
```
|
||||
node tools/regtest/rehearse.mjs # nine beats; saves the lab to tools/regtest/out/lab.json
|
||||
node tools/regtest/rehearse.mjs # twelve beats; saves the lab to tools/regtest/out/lab.json
|
||||
node bin/lineage-index.mjs --from 100 --compare tools/regtest/out/lab.json
|
||||
node tools/regtest/record.mjs # refresh tests/fixtures/regtest-rehearsal.json (public data only)
|
||||
```
|
||||
|
||||
A chain can hold several rehearsals. Each one founds its own holdings, so to compare or record only the latest, pass the
|
||||
height of its funding block: `--from <height>` to the index, and the same height after the lab to `record.mjs`.
|
||||
|
||||
The rehearsal funds the lab wallet with real regtest coins (`LocalChain.importCoin`) and pays every local beat to an
|
||||
unspendable key, so nothing it signs spends a coin regtest doesn't have. After each beat it broadcasts that beat's
|
||||
transactions and mines one regtest block. `--compare` checks that every event landed in the same beat with the same
|
||||
metadata and parent, that every inscription sits in the same output, and that both fold into the same trees. Within a
|
||||
block the miner may order independent events differently from the lab; that changes nothing (`SPEC.md`, section 2).
|
||||
block the miner may order independent events differently from the lab, a join and its adoption included; that changes
|
||||
nothing (`SPEC.md`, sections 2 and 5).
|
||||
|
||||
`out/` holds the lab backup, test keys included, and is not committed.
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import { Script, Tx } from '@cmdcode/tapscript';
|
||||
import { TestWallet } from '../../src/adapters/wallet.js';
|
||||
import { MetadataIndex } from '../../src/adapters/metadata-index.js';
|
||||
import { emptyLab, encodeLab, setRule, setTempo } from '../../src/orgchain/store.js';
|
||||
import { accept, act, deposit, offer, send } from '../../src/orgchain/actions.js';
|
||||
import { accept, act, adopt, deposit, offer, sell, send, take } from '../../src/orgchain/actions.js';
|
||||
import { askId } from '../../src/orgchain/offers.js';
|
||||
import { SAT } from '../../src/orgchain/money.js';
|
||||
import { lineageEvents, reduce, rows } from '../../src/orgchain/lineage.js';
|
||||
import { bitcoind } from './rpc.mjs';
|
||||
@@ -72,13 +73,13 @@ act(lab, 'keyring', yolo, {});
|
||||
await beat("well-known and time, and yolopreneur's keyring");
|
||||
send(lab, yolo, time, 40 * SAT);
|
||||
send(lab, yolo, wk, 10 * SAT);
|
||||
act(lab, 'birth', wk, { name: 'mailr', kind: 'org' });
|
||||
const mailr = act(lab, 'birth', wk, { name: 'mailr', kind: 'org' });
|
||||
const lineage = act(lab, 'birth', wk, { name: 'lineage', kind: 'org' });
|
||||
const luna = act(lab, 'birth', time, { name: 'luna', kind: 'agent' }), sol = act(lab, 'birth', time, { name: 'sol', kind: 'agent' });
|
||||
act(lab, 'birth', time, { name: 'astra', kind: 'agent' });
|
||||
await beat('two sends and five births');
|
||||
send(lab, wk, lineage, 2 * SAT);
|
||||
for (const name of ['docscope', 'dollhouse', 'doodleloop', 'hearthframe']) act(lab, 'birth', time, { name, kind: 'org' });
|
||||
const [docscope] = ['docscope', 'dollhouse', 'doodleloop', 'hearthframe'].map(name => act(lab, 'birth', time, { name, kind: 'org' }));
|
||||
await beat("time's ventures");
|
||||
send(lab, time, sol, SAT);
|
||||
send(lab, time, luna, 0.5 * SAT);
|
||||
@@ -104,9 +105,21 @@ send(lab, scout, wk, 0.1 * SAT);
|
||||
act(lab, 'award', wk, { to: scout, skill: 'listen', belt: 'white' });
|
||||
act(lab, 'keyring', scout, {});
|
||||
await beat("scout pays well-known, which awards it a belt, and scout's keyring");
|
||||
// Both sides of a deal (v1.12). An ask: well-known signs mailr's input SIGHASH_SINGLE|ANYONECANPAY, and lineage takes
|
||||
// it behind a dummy of its own, then adopts mailr, which joins it and moves to its new keys. An offer: acme bids for
|
||||
// docscope, time accepts, and acme adopts it a beat later, while scout takes lineage's ask for the launch kit.
|
||||
take(lab, askId(sell(lab, mailr, SAT)), lineage);
|
||||
await beat('lineage takes the ask for mailr and adopts it');
|
||||
accept(lab, offer(lab, docscope, acme, 0.5 * SAT).txid);
|
||||
await beat('acme buys docscope on an offer time accepts');
|
||||
adopt(lab, docscope, acme);
|
||||
take(lab, askId(sell(lab, kit, 0.2 * SAT)), scout);
|
||||
await beat('acme adopts docscope, and scout takes the ask for the launch kit');
|
||||
|
||||
const live = reduce(lineageEvents(new MetadataIndex(lab.chain)), { pending: true });
|
||||
for (const root of live.roots) console.log(rows(live, root.id).map(r => (r.type === 'group' ? `${r.guide}${r.label}` : `${r.guide}${r.path} ${r.node.name}`)).join('\n'));
|
||||
for (const root of live.roots) {
|
||||
console.log(rows(live, root.id).map(r => (r.type === 'group' ? `${r.guide}${r.label}` : `${r.guide}${r.path} ${r.node.name}${r.moved ? ' · moved' : r.away ? ' · graduated' : ''}`)).join('\n'));
|
||||
}
|
||||
mkdirSync(dirname(out), { recursive: true });
|
||||
writeFileSync(out, encodeLab(lab));
|
||||
console.log(`${beats} beats, ${sent} transactions confirmed on regtest (height ${await node('getblockcount')}); the lab is saved to ${out}`);
|
||||
Reference in new issue
Block a user