Skip to content

Commit 8b249a1

Browse files
authored
feat: masternode hard fork signal transaction payload (#301)
* feat: groundwork for mnhfsignal special tx * feat: add mnhfsignal * feat: test using an actual tx from mainnet
1 parent bd0b2c6 commit 8b249a1

File tree

9 files changed

+478
-0
lines changed

9 files changed

+478
-0
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export { MultiSigScriptHashInput } from './typings/transaction/input/MultiSigScr
6060
export { AbstractPayload };
6161
export { CoinbasePayload } from './typings/transaction/payload/CoinbasePayload';
6262
export { CommitmentTxPayload } from './typings/transaction/payload/CommitmentTxPayload';
63+
export { MnHfSignalPayload } from './typings/transaction/payload/MnHfSignalPayload';
6364
export { ProRegTxPayload } from './typings/transaction/payload/ProRegTxPayload';
6465
export { ProUpRegTxPayload } from './typings/transaction/payload/ProUpRegTxPayload';
6566
export { ProUpRevTxPayload } from './typings/transaction/payload/ProUpRevTxPayload';

lib/constants/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = {
2424
TRANSACTION_PROVIDER_UPDATE_REVOKE: 4,
2525
TRANSACTION_COINBASE: 5,
2626
TRANSACTION_QUORUM_COMMITMENT: 6,
27+
TRANSACTION_MASTERNODE_HARD_FORK_SIGNAL: 7,
2728
TRANSACTION_ASSET_LOCK: 8,
2829
TRANSACTION_ASSET_UNLOCK: 9,
2930
},

lib/transaction/payload/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Payload.ProTxUpServPayload = require('./proupservtxpayload');
1010
Payload.CoinbasePayload = require('./coinbasepayload');
1111
Payload.constants = require('../../constants');
1212
Payload.CommitmentTxPayload = require('./commitmenttxpayload');
13+
Payload.MnHfSignalPayload = require('./mnhfsignalpayload');
1314
Payload.AssetLockPayload = require('./assetlockpayload');
1415
Payload.AssetUnlockPayload = require('./assetunlockpayload');
1516

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/* eslint-disable */
2+
// TODO: Remove previous line and work through linting issues at next edit
3+
4+
var Preconditions = require('../../util/preconditions');
5+
var BufferWriter = require('../../encoding/bufferwriter');
6+
var BufferReader = require('../../encoding/bufferreader');
7+
var AbstractPayload = require('./abstractpayload');
8+
var utils = require('../../util/js');
9+
const _ = require('lodash');
10+
11+
var isUnsignedInteger = utils.isUnsignedInteger;
12+
13+
var CURRENT_PAYLOAD_VERSION = 1;
14+
15+
/**
16+
* @typedef {Object} MnHfSignalPayloadJSON
17+
* @property {number} version
18+
* @property {Object} signal
19+
* @property {number} signal.versionBit
20+
* @property {string} signal.quorumHash
21+
* @property {string} signal.sig
22+
*/
23+
24+
/**
25+
* @class MnHfSignalPayload
26+
* @property {number} version
27+
* @property {Object} signal
28+
* @property {number} signal.versionBit
29+
* @property {string} signal.quorumHash
30+
* @property {string} signal.sig
31+
*/
32+
function MnHfSignalPayload() {
33+
AbstractPayload.call(this);
34+
this.version = CURRENT_PAYLOAD_VERSION;
35+
this.signal = {
36+
versionBit: 0,
37+
quorumHash: '',
38+
sig: ''
39+
};
40+
}
41+
42+
MnHfSignalPayload.prototype = Object.create(AbstractPayload.prototype);
43+
MnHfSignalPayload.prototype.constructor = AbstractPayload;
44+
45+
/* Static methods */
46+
47+
/**
48+
* Parse raw payload
49+
* @param {Buffer} rawPayload
50+
* @return {MnHfSignalPayload}
51+
*/
52+
MnHfSignalPayload.fromBuffer = function (rawPayload) {
53+
var payloadBufferReader = new BufferReader(rawPayload);
54+
var payload = new MnHfSignalPayload();
55+
56+
payload.version = payloadBufferReader.readUInt8();
57+
payload.signal.versionBit = payloadBufferReader.readUInt8();
58+
59+
// Reverse the quorumHash to correct the byte order (from little-endian to big-endian)
60+
payload.signal.quorumHash = payloadBufferReader.read(32).toString('hex');
61+
62+
payload.signal.sig = payloadBufferReader.read(96).toString('hex');
63+
64+
if (!payloadBufferReader.finished()) {
65+
throw new Error('Failed to parse payload: raw payload is bigger than expected.');
66+
}
67+
68+
payload.validate();
69+
return payload;
70+
};
71+
72+
/**
73+
* Create new instance of payload from JSON
74+
* @param {string|MnHfSignalPayloadJSON} payloadJson
75+
* @return {MnHfSignalPayload}
76+
*/
77+
MnHfSignalPayload.fromJSON = function fromJSON(payloadJson) {
78+
var payload = new MnHfSignalPayload();
79+
payload.version = payloadJson.version || CURRENT_PAYLOAD_VERSION;
80+
payload.signal.versionBit = payloadJson.signal.versionBit;
81+
payload.signal.quorumHash = payloadJson.signal.quorumHash;
82+
payload.signal.sig = payloadJson.signal.sig;
83+
84+
payload.validate();
85+
return payload;
86+
};
87+
88+
/* Instance methods */
89+
90+
/**
91+
* Validates payload data
92+
* @return {boolean}
93+
*/
94+
MnHfSignalPayload.prototype.validate = function () {
95+
Preconditions.checkArgument(
96+
isUnsignedInteger(this.version),
97+
'Expect version to be an unsigned integer'
98+
);
99+
100+
Preconditions.checkArgument(
101+
this.version !== 0 && this.version <= CURRENT_PAYLOAD_VERSION,
102+
'Invalid version'
103+
);
104+
105+
Preconditions.checkArgument(
106+
isUnsignedInteger(this.signal.versionBit) && this.signal.versionBit <= 255,
107+
'Expect signal.versionBit to be an unsigned 8-bit integer'
108+
);
109+
110+
Preconditions.checkArgument(
111+
utils.isSha256HexString(this.signal.quorumHash),
112+
'Expect signal.quorumHash to be a valid 32-byte SHA256 hex string'
113+
);
114+
115+
Preconditions.checkArgument(
116+
utils.isHexaString(this.signal.sig) && Buffer.from(this.signal.sig, 'hex').length === 96,
117+
'Expect signal.sig to be a valid 96-byte hex string'
118+
);
119+
120+
return true;
121+
};
122+
123+
/**
124+
* Serializes payload to JSON
125+
* @return {MnHfSignalPayloadJSON}
126+
*/
127+
MnHfSignalPayload.prototype.toJSON = function toJSON() {
128+
this.validate();
129+
return {
130+
version: this.version,
131+
signal: {
132+
versionBit: this.signal.versionBit,
133+
quorumHash: this.signal.quorumHash,
134+
sig: this.signal.sig
135+
}
136+
};
137+
};
138+
139+
/**
140+
* Serialize payload to buffer
141+
* @return {Buffer}
142+
*/
143+
MnHfSignalPayload.prototype.toBuffer = function toBuffer() {
144+
this.validate();
145+
var payloadBufferWriter = new BufferWriter();
146+
147+
payloadBufferWriter.writeUInt8(this.version);
148+
payloadBufferWriter.writeUInt8(this.signal.versionBit);
149+
150+
// Reverse the quorumHash to write in little-endian format
151+
payloadBufferWriter.write(Buffer.from(this.signal.quorumHash, 'hex'));
152+
153+
payloadBufferWriter.write(Buffer.from(this.signal.sig, 'hex'));
154+
155+
return payloadBufferWriter.toBuffer();
156+
};
157+
158+
/**
159+
* Copy payload instance
160+
* @return {MnHfSignalPayload}
161+
*/
162+
MnHfSignalPayload.prototype.copy = function copy() {
163+
return MnHfSignalPayload.fromJSON(this.toJSON());
164+
};
165+
166+
module.exports = MnHfSignalPayload;

lib/transaction/payload/payload.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var ProRegTxPayload = require('./proregtxpayload');
1010
var ProTxUpServPayload = require('./proupservtxpayload');
1111
var ProUpRegTxPayload = require('./proupregtxpayload');
1212
var ProUpRevTxPayload = require('./prouprevtxpayload');
13+
var MnHfSignalPayload = require('./mnhfsignalpayload');
1314
var AssetLockPayload = require('./assetlockpayload');
1415
var AssetUnlockPayload = require('./assetunlockpayload');
1516

@@ -25,6 +26,8 @@ PayloadClasses[RegisteredPayloadTypes.TRANSACTION_PROVIDER_UPDATE_REGISTRAR] =
2526
ProUpRegTxPayload;
2627
PayloadClasses[RegisteredPayloadTypes.TRANSACTION_PROVIDER_UPDATE_REVOKE] =
2728
ProUpRevTxPayload;
29+
PayloadClasses[RegisteredPayloadTypes.TRANSACTION_MASTERNODE_HARD_FORK_SIGNAL] =
30+
MnHfSignalPayload;
2831
PayloadClasses[RegisteredPayloadTypes.TRANSACTION_ASSET_LOCK] =
2932
AssetLockPayload;
3033
PayloadClasses[RegisteredPayloadTypes.TRANSACTION_ASSET_UNLOCK] =

test-d/index.test-d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import type {
4141
AssetUnlockPayload,
4242
CoinbasePayload,
4343
CommitmentTxPayload,
44+
MnHfSignalPayload,
4445
ProRegTxPayload,
4546
ProUpRegTxPayload,
4647
ProUpRevTxPayload,

0 commit comments

Comments
 (0)