Skip to content

Commit

Permalink
Merge 15a105a into 7826128
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Sep 8, 2020
2 parents 7826128 + 15a105a commit e2fe32f
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 76 deletions.
8 changes: 6 additions & 2 deletions lib/wallet/txdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -960,10 +960,14 @@ class TXDB {

// FINALIZE is a special case: locked coins _leave_ the wallet.
if (tx.output(i) && tx.covenant(i).isFinalize()) {
if (!block)
if (!block) {
state.ulocked(path, -tx.outputs[i].value);
else
} else {
state.clocked(path, -tx.outputs[i].value);
// This is the first time we've seen this tx and it is in a block
// (probably from a rescan). Update unconfirmed locked balance also.
state.ulocked(path, -tx.outputs[i].value);
}
}

if (!block) {
Expand Down
299 changes: 225 additions & 74 deletions test/wallet-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,8 @@ describe('Wallet', function() {
let start;
// The main test wallet, and wallet that will receive the FINALIZE.
let wallet, recip;
// Store balance data before rescan to ensure rescan was complete
let recipBalBefore, senderBalBefore;

// Hack required to focus test on txdb mechanics.
// We don't otherwise need WalletDB or Blockchain
Expand Down Expand Up @@ -2153,21 +2155,21 @@ describe('Wallet', function() {
uTXCount++;

// Check
let senderBal = await wallet.getBalance();
assert.strictEqual(senderBal.tx, 6);
assert.strictEqual(senderBal.coin, 4);
assert.strictEqual(senderBal.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal.unconfirmed, fund - (uTXCount * fee));
assert.strictEqual(senderBal.ulocked, secondHighest);
assert.strictEqual(senderBal.clocked, secondHighest);

let recipBal = await recip.getBalance();
assert.strictEqual(recipBal.tx, 0);
assert.strictEqual(recipBal.coin, 0);
assert.strictEqual(recipBal.confirmed, 0);
assert.strictEqual(recipBal.unconfirmed, 0);
assert.strictEqual(recipBal.ulocked, 0);
assert.strictEqual(recipBal.clocked, 0);
const senderBal1 = await wallet.getBalance();
assert.strictEqual(senderBal1.tx, 6);
assert.strictEqual(senderBal1.coin, 4);
assert.strictEqual(senderBal1.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal1.unconfirmed, fund - (uTXCount * fee));
assert.strictEqual(senderBal1.ulocked, secondHighest);
assert.strictEqual(senderBal1.clocked, secondHighest);

const recipBal1 = await recip.getBalance();
assert.strictEqual(recipBal1.tx, 0);
assert.strictEqual(recipBal1.coin, 0);
assert.strictEqual(recipBal1.confirmed, 0);
assert.strictEqual(recipBal1.unconfirmed, 0);
assert.strictEqual(recipBal1.ulocked, 0);
assert.strictEqual(recipBal1.clocked, 0);

// Confirm TRANSFER
const block = {
Expand All @@ -2179,21 +2181,21 @@ describe('Wallet', function() {
cTXCount++;

// Check
senderBal = await wallet.getBalance();
assert.strictEqual(senderBal.tx, 6);
assert.strictEqual(senderBal.coin, 4);
assert.strictEqual(senderBal.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal.unconfirmed, fund - (uTXCount * fee));
assert.strictEqual(senderBal.ulocked, secondHighest);
assert.strictEqual(senderBal.clocked, secondHighest);

recipBal = await recip.getBalance();
assert.strictEqual(recipBal.tx, 0);
assert.strictEqual(recipBal.coin, 0);
assert.strictEqual(recipBal.confirmed, 0);
assert.strictEqual(recipBal.unconfirmed, 0);
assert.strictEqual(recipBal.ulocked, 0);
assert.strictEqual(recipBal.clocked, 0);
const senderBal2 = await wallet.getBalance();
assert.strictEqual(senderBal2.tx, 6);
assert.strictEqual(senderBal2.coin, 4);
assert.strictEqual(senderBal2.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal2.unconfirmed, fund - (uTXCount * fee));
assert.strictEqual(senderBal2.ulocked, secondHighest);
assert.strictEqual(senderBal2.clocked, secondHighest);

const recipBal2 = await recip.getBalance();
assert.strictEqual(recipBal2.tx, 0);
assert.strictEqual(recipBal2.coin, 0);
assert.strictEqual(recipBal2.confirmed, 0);
assert.strictEqual(recipBal2.unconfirmed, 0);
assert.strictEqual(recipBal2.ulocked, 0);
assert.strictEqual(recipBal2.clocked, 0);
});

it('should send and confirm FINALIZE', async () => {
Expand All @@ -2204,23 +2206,23 @@ describe('Wallet', function() {
uTXCount++;

// Check
let senderBal = await wallet.getBalance();
assert.strictEqual(senderBal.tx, 7);
const senderBal3 = await wallet.getBalance();
assert.strictEqual(senderBal3.tx, 7);
// One less wallet coin because name UTXO belongs to recip now
assert.strictEqual(senderBal.coin, 3);
assert.strictEqual(senderBal.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBal.ulocked, 0);
assert.strictEqual(senderBal.clocked, secondHighest);
assert.strictEqual(senderBal3.coin, 3);
assert.strictEqual(senderBal3.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal3.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBal3.ulocked, 0);
assert.strictEqual(senderBal3.clocked, secondHighest);

// The name and its locked value now belong to recipient
let recipBal = await recip.getBalance();
assert.strictEqual(recipBal.tx, 1);
assert.strictEqual(recipBal.coin, 1);
assert.strictEqual(recipBal.confirmed, 0);
assert.strictEqual(recipBal.unconfirmed, secondHighest);
assert.strictEqual(recipBal.ulocked, secondHighest);
assert.strictEqual(recipBal.clocked, 0);
const recipBal3 = await recip.getBalance();
assert.strictEqual(recipBal3.tx, 1);
assert.strictEqual(recipBal3.coin, 1);
assert.strictEqual(recipBal3.confirmed, 0);
assert.strictEqual(recipBal3.unconfirmed, secondHighest);
assert.strictEqual(recipBal3.ulocked, secondHighest);
assert.strictEqual(recipBal3.clocked, 0);

// Confirm FINALIZE
const block = {
Expand All @@ -2234,21 +2236,31 @@ describe('Wallet', function() {
cTXCount++;

// Check
senderBal = await wallet.getBalance();
assert.strictEqual(senderBal.tx, 7);
assert.strictEqual(senderBal.coin, 3);
assert.strictEqual(senderBal.confirmed, fund - secondHighest - (cTXCount * fee));
assert.strictEqual(senderBal.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBal.ulocked, 0);
assert.strictEqual(senderBal.clocked, 0);

recipBal = await recip.getBalance();
assert.strictEqual(recipBal.tx, 1);
assert.strictEqual(recipBal.coin, 1);
assert.strictEqual(recipBal.confirmed, secondHighest);
assert.strictEqual(recipBal.unconfirmed, secondHighest);
assert.strictEqual(recipBal.ulocked, secondHighest);
assert.strictEqual(recipBal.clocked, secondHighest);
senderBalBefore = await wallet.getBalance();
assert.strictEqual(senderBalBefore.tx, 7);
assert.strictEqual(senderBalBefore.coin, 3);
assert.strictEqual(senderBalBefore.confirmed, fund - secondHighest - (cTXCount * fee));
assert.strictEqual(senderBalBefore.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBalBefore.ulocked, 0);
assert.strictEqual(senderBalBefore.clocked, 0);

recipBalBefore = await recip.getBalance();
assert.strictEqual(recipBalBefore.tx, 1);
assert.strictEqual(recipBalBefore.coin, 1);
assert.strictEqual(recipBalBefore.confirmed, secondHighest);
assert.strictEqual(recipBalBefore.unconfirmed, secondHighest);
assert.strictEqual(recipBalBefore.ulocked, secondHighest);
assert.strictEqual(recipBalBefore.clocked, secondHighest);
});

it('should have correct balance after rescan', async () => {
await wdb.rescan(0);

const senderBalAfter = await wallet.getBalance();
const recipBalAfter = await recip.getBalance();

assert.deepStrictEqual(senderBalAfter, senderBalBefore);
assert.deepStrictEqual(recipBalAfter, recipBalBefore);
});

it('should disconnect FINALIZE', async () => {
Expand All @@ -2257,21 +2269,21 @@ describe('Wallet', function() {
cTXCount--;

// Check
const senderBal = await wallet.getBalance();
assert.strictEqual(senderBal.tx, 7);
assert.strictEqual(senderBal.coin, 3);
assert.strictEqual(senderBal.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBal.ulocked, 0);
assert.strictEqual(senderBal.clocked, secondHighest);

const recipBal = await recip.getBalance();
assert.strictEqual(recipBal.tx, 1);
assert.strictEqual(recipBal.coin, 1);
assert.strictEqual(recipBal.confirmed, 0);
assert.strictEqual(recipBal.unconfirmed, secondHighest);
assert.strictEqual(recipBal.ulocked, secondHighest);
assert.strictEqual(recipBal.clocked, 0);
const senderBal4 = await wallet.getBalance();
assert.strictEqual(senderBal4.tx, 7);
assert.strictEqual(senderBal4.coin, 3);
assert.strictEqual(senderBal4.confirmed, fund - (cTXCount * fee));
assert.strictEqual(senderBal4.unconfirmed, fund - secondHighest - (uTXCount * fee));
assert.strictEqual(senderBal4.ulocked, 0);
assert.strictEqual(senderBal4.clocked, secondHighest);

const recipBal4 = await recip.getBalance();
assert.strictEqual(recipBal4.tx, 1);
assert.strictEqual(recipBal4.coin, 1);
assert.strictEqual(recipBal4.confirmed, 0);
assert.strictEqual(recipBal4.unconfirmed, secondHighest);
assert.strictEqual(recipBal4.ulocked, secondHighest);
assert.strictEqual(recipBal4.clocked, 0);
});
});

Expand All @@ -2280,11 +2292,20 @@ describe('Wallet', function() {
const workers = new WorkerPool({ enabled });
const wdb = new WalletDB({ network, workers });
const name = 'satoshi';
const nameHash = rules.hashName(name);
const value = 1e6;
const lockup = 2e6;
const secondHighest = value - 1;
const fee = 10000;
let start;
let wallet;

// Hack required to focus test on txdb mechanics.
// We don't otherwise need WalletDB or Blockchain
wdb.getRenewalBlock = () => {
return network.genesis.hash;
};

before(async () => {
await wdb.open();
wallet = await wdb.create();
Expand Down Expand Up @@ -2344,6 +2365,7 @@ describe('Wallet', function() {
time: Date.now()
};
await wallet.txdb.add(open.toTX(), block);
start = wdb.height;

// Check
bal = await wallet.getBalance();
Expand Down Expand Up @@ -2420,6 +2442,135 @@ describe('Wallet', function() {
assert.strictEqual(bal.ulocked, value);
assert.strictEqual(bal.clocked, value);
});

it('should add external REVEAL to txdb', async () => {
// The goal is to have a "second-highest" bid
// so the wallet doesn't win the name for free.
// We can skip the whole BID/lockup thing for these tests.

const output = new Output();
output.value = secondHighest;
output.covenant.type = types.REVEAL;
output.covenant.pushHash(nameHash);
output.covenant.pushU32(start);
output.covenant.push(Buffer.from(name, 'ascii'));
output.covenant.pushHash(Buffer.alloc(32));

const mtx = new MTX();
mtx.outputs.push(output);

// Confirm external REVEAL
const block = {
height: wdb.height + 1,
hash: Buffer.alloc(32),
time: Date.now()
};
await wallet.txdb.add(mtx.toTX(), block);
});

it('should confirm new REGISTER', async () => {
// Advance to close
wdb.height += network.names.revealPeriod;

const resource = Resource.fromJSON({records: []});
const register = await wallet.createUpdate(name, resource, {hardFee: fee});

// Check
let bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 4);
assert.strictEqual(bal.coin, 4);
assert.strictEqual(bal.confirmed, 10e6 - (3 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - (3 * fee));
assert.strictEqual(bal.ulocked, value);
assert.strictEqual(bal.clocked, value);

// Confirm REGISTER
const block = {
height: wdb.height + 1,
hash: Buffer.alloc(32),
time: Date.now()
};
await wallet.txdb.add(register.toTX(), block);

// Check
bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 5);
// Wallet coin count doesn't change:
// REVEAL + fee money -> REGISTER + change
assert.strictEqual(bal.coin, 4);
assert.strictEqual(bal.confirmed, 10e6 - (4 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - (4 * fee));
assert.strictEqual(bal.ulocked, secondHighest);
assert.strictEqual(bal.clocked, secondHighest);
});

it('should confirm new TRANSFER', async () => {
const addr = new Address({
version: 0,
hash: Buffer.alloc(20, 0x88)
});
const transfer = await wallet.createTransfer(name, addr, {hardFee: fee});

// Check
let bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 5);
assert.strictEqual(bal.coin, 4);
assert.strictEqual(bal.confirmed, 10e6 - (4 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - (4 * fee));
assert.strictEqual(bal.ulocked, secondHighest);
assert.strictEqual(bal.clocked, secondHighest);

// Confirm TRANSFER
const block = {
height: wdb.height + 1,
hash: Buffer.alloc(32),
time: Date.now()
};
await wallet.txdb.add(transfer.toTX(), block);

// Check
bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 6);
assert.strictEqual(bal.coin, 4);
assert.strictEqual(bal.confirmed, 10e6 - (5 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - (5 * fee));
assert.strictEqual(bal.ulocked, secondHighest);
assert.strictEqual(bal.clocked, secondHighest);
});

it('should confirm new FINALIZE', async () => {
// Advance past lockup
wdb.height += network.names.transferLockup + 1;

const finalize = await wallet.createFinalize(name, {hardFee: fee});

// Check
let bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 6);
assert.strictEqual(bal.coin, 4);
assert.strictEqual(bal.confirmed, 10e6 - (5 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - (5 * fee));
assert.strictEqual(bal.ulocked, secondHighest);
assert.strictEqual(bal.clocked, secondHighest);

// Confirm FINALIZE
const block = {
height: wdb.height + 1,
hash: Buffer.alloc(32),
time: Date.now()
};
await wallet.txdb.add(finalize.toTX(), block);

// Check
bal = await wallet.getBalance();
assert.strictEqual(bal.tx, 7);
// Coin count reduced by giving away name UTXO
assert.strictEqual(bal.coin, 3);
assert.strictEqual(bal.confirmed, 10e6 - secondHighest - (6 * fee));
assert.strictEqual(bal.unconfirmed, 10e6 - secondHighest - (6 * fee));
assert.strictEqual(bal.ulocked, 0);
assert.strictEqual(bal.clocked, 0);
});
});

describe('Node Integration', function() {
Expand Down

0 comments on commit e2fe32f

Please sign in to comment.