Skip to content

Commit

Permalink
feat: update coinbase payload accroding to changes in Core v20 (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
jawid-h authored May 5, 2023
1 parent 2828471 commit 31cc896
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 9 deletions.
52 changes: 52 additions & 0 deletions lib/transaction/payload/coinbasepayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var BufferWriter = require('../../encoding/bufferwriter');
var BufferReader = require('../../encoding/bufferreader');
var AbstractPayload = require('./abstractpayload');
var utils = require('../../util/js');
var BN = require('../../crypto/bn');

var isUnsignedInteger = utils.isUnsignedInteger;
var isHexString = utils.isHexaString;
Expand All @@ -20,6 +21,9 @@ var HASH_SIZE = constants.SHA256_HASH_SIZE;
* @property {number} height
* @property {string} merkleRootMNList
* @property {string} merkleRootQuorums
* @property {number} bestCLHeight
* @property {Buffer} bestCLSignature
* @property {number} assetLockedAmount
*/

/**
Expand All @@ -28,6 +32,9 @@ var HASH_SIZE = constants.SHA256_HASH_SIZE;
* @property {number} height
* @property {string} merkleRootMNList
* @property {string} merkleRootQuorums
* @property {number} bestCLHeight
* @property {Buffer} bestCLSignature
* @property {number} assetLockedAmount
*/
function CoinbasePayload() {
AbstractPayload.call(this);
Expand Down Expand Up @@ -60,6 +67,12 @@ CoinbasePayload.fromBuffer = function (rawPayload) {
.toString('hex');
}

if (payload.version >= 3) {
payload.bestCLHeight = payloadBufferReader.readVarintNum();
payload.bestCLSignature = payloadBufferReader.read(96);
payload.assetLockedAmount = payloadBufferReader.readUInt64LEBN();
}

if (!payloadBufferReader.finished()) {
throw new Error(
'Failed to parse payload: raw payload is bigger than expected.'
Expand All @@ -84,6 +97,12 @@ CoinbasePayload.fromJSON = function fromJSON(payloadJson) {
payload.merkleRootQuorums = payloadJson.merkleRootQuorums;
}

if (payload.version >= 3) {
payload.bestCLHeight = payloadJson.bestCLHeight;
payload.bestCLSignature = Buffer.from(payloadJson.bestCLSignature, 'hex');
payload.assetLockedAmount = payloadJson.assetLockedAmount;
}

payload.validate();
return payload;
};
Expand Down Expand Up @@ -123,6 +142,28 @@ CoinbasePayload.prototype.validate = function () {
'Invalid merkleRootQuorums size'
);
}
if (this.version >= 3) {
Preconditions.checkArgument(
isUnsignedInteger(this.bestCLHeight),
'Expect bestCLHeight to be an unsigned integer'
);
Preconditions.checkArgument(
Buffer.isBuffer(this.bestCLSignature),
'Expect bestCLSignature to be a buffer'
);
Preconditions.checkArgument(
this.bestCLSignature.length === 96,
'Invalid bestCLSignature size'
);
Preconditions.checkArgument(
BN.isBN(this.assetLockedAmount),
'Expect assetLockedAmount to be an instance of BN'
);
Preconditions.checkArgument(
isUnsignedInteger(this.assetLockedAmount.toNumber()),
'Expect assetLockedAmount to be an unsigned integer'
);
}
return true;
};

Expand All @@ -140,6 +181,11 @@ CoinbasePayload.prototype.toJSON = function toJSON() {
if (this.version >= 2) {
json.merkleRootQuorums = this.merkleRootQuorums;
}
if (this.version >= 3) {
json.bestCLHeight = this.bestCLHeight;
json.bestCLSignature = this.bestCLSignature.toString('hex');
json.assetLockedAmount = this.assetLockedAmount;
}
return json;
};

Expand All @@ -162,6 +208,12 @@ CoinbasePayload.prototype.toBuffer = function toBuffer() {
);
}

if (this.version >= 3) {
payloadBufferWriter.writeVarintNum(this.bestCLHeight);
payloadBufferWriter.write(this.bestCLSignature);
payloadBufferWriter.writeUInt64LEBN(new BN(this.assetLockedAmount));
}

return payloadBufferWriter.toBuffer();
};

Expand Down
76 changes: 67 additions & 9 deletions test/transaction/payload/coinbasepayload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,32 @@ var sinon = require('sinon');

var DashcoreLib = require('../../../index');

var BN = require('../../../lib/crypto/bn');

var CoinbasePayload = DashcoreLib.Transaction.Payload.CoinbasePayload;

var merkleRootMNList =
'a1d4f77f5c85a9d56293878edda45ba6fb3e433e6b9bc278c0f4c5799748b975';
var merkleRootQuorums =
'9491099bb93b789d8628acce8f8a84c0f4af8196d3dd6c2427aca0ee702fcc90';
var bestCLHeight = 42;
var bestCLSignature = Buffer.alloc(96, 1);
var assetLockedAmount = new BN(1000);

var validCoinbasePayloadJSON = {
version: 2,
version: 3,
height: 80672,
merkleRootMNList: merkleRootMNList,
merkleRootQuorums: merkleRootQuorums,
bestCLHeight: bestCLHeight,
bestCLSignature: bestCLSignature,
assetLockedAmount: assetLockedAmount,
};
// Contains same data as JSON above
// 0200 is 16-bit unsigned 2, 203b0100 is 32 bit unsigned 80672, everything else is a hash.
var validCoinbasePayloadHexString =
'0200203b010075b9489779c5f4c078c29b6b3e433efba65ba4dd8e879362d5a9855c7ff7d4a190cc2f70eea0ac27246cddd39681aff4c0848a8fceac28869d783bb99b099194';
var validCoinbasePayloadBuffer = Buffer.from(
validCoinbasePayloadHexString,
'hex'
);
var validCoinbasePayload = CoinbasePayload.fromJSON(validCoinbasePayloadJSON);
var validCoinbasePayloadBuffer = validCoinbasePayload.toBuffer();
var validCoinbasePayloadHexString = validCoinbasePayloadBuffer.toString('hex');

describe('CoinbasePayload', function () {
describe('.fromBuffer', function () {
Expand All @@ -43,10 +47,13 @@ describe('CoinbasePayload', function () {
var payload = CoinbasePayload.fromBuffer(validCoinbasePayloadBuffer);

expect(payload).to.be.an.instanceOf(CoinbasePayload);
expect(payload.version).to.be.equal(2);
expect(payload.version).to.be.equal(3);
expect(payload.height).to.be.equal(80672);
expect(payload.merkleRootMNList).to.be.equal(merkleRootMNList);
expect(payload.merkleRootQuorums).to.be.equal(merkleRootQuorums);
expect(payload.bestCLHeight).to.be.equal(bestCLHeight);
expect(payload.bestCLSignature).to.be.deep.equal(bestCLSignature);
expect(payload.assetLockedAmount).to.be.deep.equal(assetLockedAmount);
expect(payload.validate.callCount).to.be.equal(1);
});

Expand All @@ -73,9 +80,12 @@ describe('CoinbasePayload', function () {
var payload = CoinbasePayload.fromJSON(validCoinbasePayloadJSON);

expect(payload).to.be.an.instanceOf(CoinbasePayload);
expect(payload.version).to.be.equal(2);
expect(payload.version).to.be.equal(3);
expect(payload.height).to.be.equal(80672);
expect(payload.merkleRootMNList).to.be.equal(merkleRootMNList);
expect(payload.bestCLHeight).to.be.equal(bestCLHeight);
expect(payload.bestCLSignature).to.be.deep.equal(bestCLSignature);
expect(payload.assetLockedAmount).to.be.deep.equal(assetLockedAmount);
expect(payload.validate.callCount).to.be.equal(1);
});

Expand Down Expand Up @@ -231,6 +241,42 @@ describe('CoinbasePayload', function () {
}).not.to.throw;
}
});
it('Should allow only unsigned integer as bestCLHeight', function () {
var payload = validCoinbasePayload.copy();

payload.bestCLHeight = -10;

expect(function () {
payload.validate();
}).to.throw('Invalid Argument: Expect bestCLHeight to be an unsigned integer');
});
it('Should allow only 96 bytes as bestCLSignature', function () {
var payload = validCoinbasePayload.copy();

payload.bestCLSignature = Buffer.alloc(95, 1);

expect(function () {
payload.validate();
}).to.throw('Invalid Argument: Invalid bestCLSignature size');
});
it('Should allow only BN as assetLockedAmount', function () {
var payload = validCoinbasePayload.copy();

payload.assetLockedAmount = 10;

expect(function () {
payload.validate();
}).to.throw('Invalid Argument: Expect assetLockedAmount to be an instance of BN');
});
it('Should allow only unsigned integer as assetLockedAmount', function () {
var payload = validCoinbasePayload.copy();

payload.assetLockedAmount = new BN(-10);

expect(function () {
payload.validate();
}).to.throw('Invalid Argument: Expect assetLockedAmount to be an unsigned integer');
});
});

describe('#toJSON', function () {
Expand All @@ -252,6 +298,11 @@ describe('CoinbasePayload', function () {
expect(payloadJSON.merkleRootMNList).to.be.equal(
payload.merkleRootMNList
);
expect(payloadJSON.bestCLHeight).to.be.equal(payload.bestCLHeight);
expect(payloadJSON.bestCLSignature).to.be.equal(payload.bestCLSignature.toString('hex'));
expect(payloadJSON.assetLockedAmount).to.be.deep.equal(
payload.assetLockedAmount
);
});
it('Should call #validate', function () {
var payload = CoinbasePayload.fromJSON(validCoinbasePayloadJSON);
Expand Down Expand Up @@ -281,6 +332,13 @@ describe('CoinbasePayload', function () {
expect(restoredPayload.merkleRootMNList).to.be.equal(
payload.merkleRootMNList
);
expect(restoredPayload.bestCLHeight).to.be.equal(payload.bestCLHeight);
expect(restoredPayload.bestCLSignature).to.be.deep.equal(
payload.bestCLSignature
);
expect(restoredPayload.assetLockedAmount).to.be.deep.equal(
payload.assetLockedAmount
);
});
it('Should call #validate', function () {
var payload = CoinbasePayload.fromJSON(validCoinbasePayloadJSON);
Expand Down

0 comments on commit 31cc896

Please sign in to comment.