Skip to content

Commit 44fab68

Browse files
committed
Merge PR #829 from '5.x-proposal'
2 parents 66d9e3c + 043076a commit 44fab68

16 files changed

+185
-19
lines changed

docs/release-notes/release-notes-5.x.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ v5.x Release notes
99
+ [Node changes](#node-changes)
1010
+ [Wallet changes](#wallet-changes)
1111
* [Changelog](#changelog)
12+
- [v5.1](#v51)
13+
* [Changelog](#changelog-1)
1214

1315
<!-- tocstop -->
1416

@@ -70,3 +72,10 @@ v5.x Release notes
7072
- \[[`9cf8cb83`](https://github.com/handshake-org/hsd/commit/9cf8cb83)] - [#776](https://github.com/handshake-org/hsd/pull/776) - **docker/docs**: Fix npm warning (@NetOpWibby)
7173
- \[[`395878a0`](https://github.com/handshake-org/hsd/commit/395878a0)] - [#775](https://github.com/handshake-org/hsd/pull/775) - **docs**: fix doc (@Falci - Fernando Falci)
7274
- \[[`fb5501c5`](https://github.com/handshake-org/hsd/commit/fb5501c5)] - [#765](https://github.com/handshake-org/hsd/pull/765) - **chore(BIP39)**: added Portuguese wordlist (@Falci - Fernando Falci)
75+
76+
# v5.1
77+
## Changelog
78+
- \[[`6b47c3a0`](https://github.com/handshake-org/hsd/commit/6b47c3a0)] - [#805](https://github.com/handshake-org/hsd/pull/805) - **SEMVER-MINOR network**: update last checkpoint (@nodech - Nodari Chkuaselidze)
79+
- \[[`15f74ccf`](https://github.com/handshake-org/hsd/commit/15f74ccf)] - [#824](https://github.com/handshake-org/hsd/pull/824) - **SEMVER-MINOR rpc**: Added totalSigs to JSON response for scriptToJSON (@Nathanwoodburn - Nathan Woodburn)
80+
- \[[`81bddcd2`](https://github.com/handshake-org/hsd/commit/81bddcd2)] - [#825](https://github.com/handshake-org/hsd/pull/825) - **wallet**: fix makeBatch to generate addresses early (@rithvikvibhu - Rithvik Vibhu)
81+
- \[[`ed27e7f6`](https://github.com/handshake-org/hsd/commit/ed27e7f6)] - [#826](https://github.com/handshake-org/hsd/pull/826) - **mempool**: more invalidation tests. (@nodech - Nodari Chkuaselidze)

lib/mempool/contractstate.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,9 @@ class ContractState {
297297
}
298298

299299
handleExpired(nameHash, items) {
300-
return this.toSet(this.updates, nameHash, items);
300+
this.toSet(this.updates, nameHash, items);
301+
this.toSet(this.reveals, nameHash, items);
302+
return this;
301303
}
302304

303305
handleOpen(nameHash, items) {
@@ -335,7 +337,7 @@ class ContractState {
335337
const state = ns.state(nextHeight, network);
336338

337339
switch (state) {
338-
case states.OPEN:
340+
case states.OPENING:
339341
this.handleOpen(nameHash, invalid);
340342
break;
341343
case states.BIDDING:

lib/node/rpc.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2978,17 +2978,21 @@ class RPC extends RPCBase {
29782978
hex: undefined,
29792979
type: Script.typesByVal[type],
29802980
reqSigs: 1,
2981+
totalSigs: 1,
29812982
p2sh: undefined
29822983
};
29832984

29842985
if (hex)
29852986
json.hex = script.toJSON();
29862987

2987-
const [m] = script.getMultisig();
2988+
const [m, n] = script.getMultisig();
29882989

29892990
if (m !== -1)
29902991
json.reqSigs = m;
29912992

2993+
if (n !== -1)
2994+
json.totalSigs = n;
2995+
29922996
return json;
29932997
}
29942998

lib/primitives/covenant.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ class Covenant extends bio.Struct {
618618
*/
619619

620620
format() {
621-
return `<Covenant: ${this.type}:${this.toString()}>`;
621+
return `<Covenant: ${typesByVal[this.type]}:${this.toString()}>`;
622622
}
623623

624624
/**

lib/protocol/networks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ main.checkpointMap = {
113113
* @default
114114
*/
115115

116-
main.lastCheckpoint = 100000;
116+
main.lastCheckpoint = 130000;
117117

118118
/**
119119
* Reward halving interval.

lib/wallet/wallet.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,14 +1716,16 @@ class Wallet extends EventEmitter {
17161716
* @param {Number} lockup
17171717
* @param {Number|String} acct
17181718
* @param {MTX?} mtx
1719-
* @returns {MTX}
1719+
* @param {Address?} addr
1720+
* @returns {Promise<MTX>}
17201721
*/
17211722

1722-
async makeBid(name, value, lockup, acct, mtx) {
1723+
async makeBid(name, value, lockup, acct, mtx, addr) {
17231724
assert(typeof name === 'string');
17241725
assert(Number.isSafeInteger(value) && value >= 0);
17251726
assert(Number.isSafeInteger(lockup) && lockup >= 0);
17261727
assert((acct >>> 0) === acct || typeof acct === 'string');
1728+
assert(addr == null || addr instanceof Address);
17271729

17281730
if (!rules.verifyName(name))
17291731
throw new Error(`Invalid name: ${name}.`);
@@ -1759,7 +1761,9 @@ class Wallet extends EventEmitter {
17591761
`Bid (${value}) exceeds lockup value (${lockup}): ${name}.`
17601762
);
17611763

1762-
const addr = await this.receiveAddress(acct);
1764+
if (!addr)
1765+
addr = await this.receiveAddress(acct);
1766+
17631767
const blind = await this.generateBlind(nameHash, addr, value);
17641768

17651769
const output = new Output();
@@ -3713,6 +3717,11 @@ class Wallet extends EventEmitter {
37133717
}
37143718
});
37153719

3720+
// Some actions accept output addresses to avoid address reuse.
3721+
// We track that by bumping receiveIndex.
3722+
const account = await this.getAccount(acct);
3723+
let receiveIndex = account.receiveDepth - 1;
3724+
37163725
// "actions" are arrays that start with a covenant type (or meta-type)
37173726
// followed by the arguments expected by the corresponding "make" function.
37183727
for (const action of actions) {
@@ -3735,10 +3744,12 @@ class Wallet extends EventEmitter {
37353744
assert(action.length === 1, 'Bad arguments for OPEN.');
37363745
await this.makeOpen(...action, force, acct, mtx);
37373746
break;
3738-
case 'BID':
3747+
case 'BID': {
37393748
assert(action.length === 3, 'Bad arguments for BID.');
3740-
await this.makeBid(...action, acct, mtx);
3749+
const address = account.deriveReceive(receiveIndex++).getAddress();
3750+
await this.makeBid(...action, acct, mtx, address);
37413751
break;
3752+
}
37423753
case 'REVEAL':
37433754
if (action.length === 1) {
37443755
await this.makeReveal(...action, acct, mtx);
@@ -3807,10 +3818,6 @@ class Wallet extends EventEmitter {
38073818
// Clean up.
38083819
// 1. Some actions MUST be the ONLY action for a name.
38093820
// i.e. no duplicate OPENs or REVOKE/FINALIZE for same name in one tx.
3810-
// 2. Some outputs may reuse same address from this.receieveAddress(acct)
3811-
// We can bump those to the next receive address,
3812-
const account = await this.getAccount(acct);
3813-
let receiveIndex = account.receiveDepth - 1;
38143821
const set = new BufferSet();
38153822
for (const output of mtx.outputs) {
38163823
const {covenant} = output;
@@ -3823,12 +3830,10 @@ class Wallet extends EventEmitter {
38233830
case types.CLAIM:
38243831
case types.OPEN:
38253832
output.address = account.deriveReceive(receiveIndex++).getAddress();
3826-
38273833
assert(!set.has(nameHash), 'Duplicate name with exclusive action.');
38283834
set.add(nameHash);
38293835
break;
38303836
case types.BID:
3831-
output.address = account.deriveReceive(receiveIndex++).getAddress();
38323837
case types.REVEAL:
38333838
case types.REDEEM:
38343839
break;

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hsd",
3-
"version": "5.0.1",
3+
"version": "5.1.0",
44
"description": "Cryptocurrency bike-shed",
55
"license": "MIT",
66
"repository": "git://github.com/handshake-org/hsd.git",

test/auction-reorg-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ describe('Auction Reorg', function() {
409409
});
410410

411411
describe('Claim Reorg', function() {
412+
this.timeout(10000);
413+
412414
const node = createNode();
413415
const {chain, miner, cpu, blocks} = node;
414416

test/auction-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ describe('Auction', function() {
483483
});
484484

485485
describe('Claim', function() {
486+
this.timeout(10000);
487+
486488
const node = createNode();
487489
const {chain, miner, cpu, blocks} = node;
488490

test/chain-checkpoints-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ describe('Checkpoints', function() {
119119
});
120120

121121
it('should CLAIM and REGISTER a reserved name', async () => {
122+
this.timeout(10000);
123+
122124
const claim = await wallet.fakeClaim('cloudflare');
123125

124126
await mineBlock(null, [claim], null, 'claim');

test/claim-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ async function mineBlocks(n, addr) {
4646

4747
describe('Reserved Name Claims', function() {
4848
this.timeout(10000);
49+
4950
before(async () => {
5051
await node.open();
5152

test/mempool-test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,8 @@ describe('Mempool', function() {
11191119
});
11201120

11211121
it('should handle reorg: name claim - DNSSEC timestamp', async () => {
1122+
this.timeout(10000);
1123+
11221124
// Mempool is empty
11231125
await mempool.reset();
11241126
assert.strictEqual(mempool.map.size, 0);
@@ -1205,6 +1207,8 @@ describe('Mempool', function() {
12051207
});
12061208

12071209
it('should handle reorg: name claim - block commitment', async () => {
1210+
this.timeout(10000);
1211+
12081212
// Mempool is empty
12091213
await mempool.reset();
12101214
assert.strictEqual(mempool.map.size, 0);

test/txstart-test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ describe('Disable TXs', function() {
7777
});
7878

7979
it('should reject claim from mempool before txStart', async () => {
80+
this.timeout(10000);
81+
8082
const claim = await wallet.fakeClaim('cloudflare');
8183

8284
try {
@@ -184,6 +186,8 @@ describe('Disable TXs', function() {
184186
});
185187

186188
it('should allow claim in mempool one block before txStart', async () => {
189+
this.timeout(10000);
190+
187191
const claim = await wallet.fakeClaim('cloudflare');
188192

189193
try {

test/wallet-importnonce-test.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
'use strict';
2+
3+
const assert = require('bsert');
4+
const FullNode = require('../lib/node/fullnode');
5+
const Network = require('../lib/protocol/network');
6+
const Address = require('../lib/primitives/address');
7+
const rules = require('../lib/covenants/rules');
8+
9+
/** @typedef {import('../lib/wallet/wallet')} Wallet */
10+
11+
const network = Network.get('regtest');
12+
13+
const node = new FullNode({
14+
memory: true,
15+
network: network.type,
16+
plugins: [require('../lib/wallet/plugin')]
17+
});
18+
19+
const { wdb } = node.require('walletdb');
20+
21+
async function mineBlocks(n, addr) {
22+
addr = addr ? addr : new Address().toString(network);
23+
for (let i = 0; i < n; i++) {
24+
const block = await node.miner.mineBlock(null, addr);
25+
await node.chain.add(block);
26+
}
27+
}
28+
29+
describe('Wallet Import Nonce', function () {
30+
/** @type {Wallet} */
31+
let walletA;
32+
33+
/** @type {Wallet} */
34+
let walletB;
35+
36+
const NAME = rules.grindName(10, 1, network);
37+
const NAMEHASH = rules.hashName(NAME);
38+
const BIDS = [
39+
{ value: 1e6, lockup: 2e6, addr: undefined }, // sendbid
40+
{ value: 2e6, lockup: 4e6, addr: undefined }, // -|sendbatch
41+
{ value: 4e6, lockup: 8e6, addr: undefined } // -|sendbatch
42+
];
43+
44+
before(async () => {
45+
await node.ensure();
46+
await node.open();
47+
48+
// Both wallets have the same seed
49+
walletA = await wdb.create();
50+
walletB = await wdb.create({ mnemonic: walletA.master.mnemonic });
51+
assert.bufferEqual(walletA.master.writeKey(), walletB.master.writeKey());
52+
});
53+
54+
after(async () => {
55+
await node.close();
56+
});
57+
58+
it('should fund wallet', async () => {
59+
await mineBlocks(2, await walletA.receiveAddress());
60+
});
61+
62+
it('should open an auction and advance to bidding period', async () => {
63+
await walletA.sendOpen(NAME, false);
64+
await mineBlocks(network.names.treeInterval + 1);
65+
});
66+
67+
it('should bid with sendbid', async () => {
68+
const bid = BIDS[0];
69+
70+
const bidTx = await walletA.sendBid(NAME, bid.value, bid.lockup);
71+
72+
// Save address for importnonce later
73+
bid.addr = bidTx.outputs[0].address;
74+
});
75+
76+
it('should bid with sendbatch', async () => {
77+
const batch = [
78+
['BID', NAME, BIDS[1].value, BIDS[1].lockup],
79+
['BID', NAME, BIDS[2].value, BIDS[2].lockup]
80+
];
81+
82+
const bidTx = await walletA.sendBatch(batch);
83+
84+
// Save address for importnonce later
85+
for (const output of bidTx.outputs) {
86+
if (!output.covenant.isBid())
87+
continue;
88+
89+
const index = BIDS.findIndex(bid => bid.lockup === output.value);
90+
BIDS[index].addr = output.address;
91+
}
92+
});
93+
94+
it('should verify bids were placed', async () => {
95+
await mineBlocks(1);
96+
const bidsA = await walletA.getBidsByName(NAME);
97+
assert.strictEqual(bidsA.length, BIDS.length);
98+
});
99+
100+
it('should not be known by other wallet', async () => {
101+
const bidsB = await walletB.getBidsByName(NAME);
102+
assert.strictEqual(bidsB.length, BIDS.length);
103+
104+
for (const bid of bidsB)
105+
assert.strictEqual(bid.value, -1);
106+
});
107+
108+
it('should be imported by other wallet', async () => {
109+
for (const bid of BIDS)
110+
await walletB.generateBlinds(NAMEHASH, bid.addr, bid.value);
111+
112+
const bidsB = await walletB.getBidsByName(NAME);
113+
assert.strictEqual(bidsB.length, BIDS.length);
114+
115+
// Ensure bids have correct true bid values
116+
for (const bid of bidsB) {
117+
const index = BIDS.findIndex(x => x.lockup === bid.lockup);
118+
assert.strictEqual(BIDS[index].value, bid.value);
119+
}
120+
});
121+
122+
it('should reaveal all bids from other wallet', async () => {
123+
await mineBlocks(network.names.biddingPeriod);
124+
125+
const revealTx = await walletB.sendRevealAll();
126+
const revealOutputs = revealTx.outputs.filter(out => out.covenant.isReveal());
127+
assert.strictEqual(revealOutputs.length, BIDS.length);
128+
});
129+
});

test/wallet-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,6 +2790,8 @@ describe('Wallet', function() {
27902790
});
27912791

27922792
it('should confirm cloudflare CLAIM', async () => {
2793+
this.timeout(10000);
2794+
27932795
// Use a fresh wallet.
27942796
const pre = await wallet.getBalance();
27952797
assert.equal(pre.tx, 0);

0 commit comments

Comments
 (0)