Skip to content

Commit

Permalink
- Add varint util class
Browse files Browse the repository at this point in the history
- Update package-lock.json
- Fix test assertion
  • Loading branch information
nathanieliov committed May 28, 2024
1 parent a83cacc commit d504205
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 100 deletions.
9 changes: 7 additions & 2 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const expect = require('chai').expect
const { ensure0x } = require('../utils');
const { ensure0x, removePrefix0x} = require('../utils');
const whitelistingAssertions = require('../assertions/whitelisting');
const rskUtils = require('../rsk-utils');
const CustomError = require('../CustomError');
Expand All @@ -10,6 +10,7 @@ const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivatio
const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter');
const { sendTxToBridge, sendPegin, ensurePeginIsRegistered, donateToBridge } = require('../2wp-utils');
const { waitAndUpdateBridge } = require('../rsk-utils');
const {VarInt} = require("../varint");

const DONATION_AMOUNT = 250;
const REJECTED_REASON = 1;
Expand Down Expand Up @@ -180,7 +181,11 @@ const execute = (description, getRskHost) => {
if (isLovell700AlreadyActive) {
const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, 'pegout_transaction_created');
expect(pegoutTransactionCreatedEvent).to.not.be.null;
expect(pegoutTransactionCreatedEvent.arguments.utxoOutpointValues.includes("fe80f0fa02")).to.be.true;
let utxoOutpointValuesAsHex = pegoutTransactionCreatedEvent.arguments.utxoOutpointValues;

// 0xfe80f0fa02 = 50000000
const expectedResult = ensure0x(Buffer.from(new VarInt(pegoutValueInSatoshis).encode()).toString("hex"));
expect(utxoOutpointValuesAsHex).to.equal(expectedResult, "Outpoint values are different.");
}
};

Expand Down
65 changes: 65 additions & 0 deletions lib/varint-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const { expect } = require('chai');
const { VarInt, Utils } = require('./varint');

describe('VarInt Tests', function() {

it('testBytes', function() {
let a = new VarInt(10);
expect(a.getSizeInBytes()).to.equal(1);
expect(a.encode().length).to.equal(1);
expect(new VarInt(a.encode(), 0).value).to.equal(10n);
});

it('testShorts', function() {
let a = new VarInt(64000);
expect(a.getSizeInBytes()).to.equal(3);
expect(a.encode().length).to.equal(3);
expect(new VarInt(a.encode(), 0).value).to.equal(64000n);
});

it('testShortFFFF', function() {
let a = new VarInt(0xFFFF);
expect(a.getSizeInBytes()).to.equal(3);
expect(a.encode().length).to.equal(3);
expect(new VarInt(a.encode(), 0).value).to.equal(0xFFFFn);
});

it('testSizeOfNegativeInt', function() {
expect(VarInt.sizeOf(-1n)).to.equal(new VarInt(-1n).encode().length);
});

it('testMaxInt', function() {
let varInt = new VarInt(BigInt(Number.MAX_SAFE_INTEGER));
console.log(Buffer.from(varInt.encode()).toString('hex'));
});

it('testDeserializeListOfValuesInHex', function() {
let expectedValues = [14435729n, 255n, 187n, 13337n];
let values = Buffer.from('FE9145DC00FDFF00BBFD1934', 'hex');
let offset = 0;
let idx = 0;
while (values.length > offset) {
let varIntValue = new VarInt(values, offset);
offset += varIntValue.getSizeInBytes();
expect(varIntValue.value).to.equal(expectedValues[idx]);
idx++;
console.log(new Intl.NumberFormat().format(varIntValue.value));
}
});

it('testSerializeListOfValuesInHex', function() {
// FF0040075AF0750700
const maxBitcoin = 2100000000000000n;
let values = [maxBitcoin, 14435729n, 255n, 187n, 13337n];
let stream = [];
values.forEach(value => {
let varIntValue = new VarInt(value);
console.log(Buffer.from(varIntValue.encode()).toString('hex'));
stream = stream.concat(Array.from(varIntValue.encode()));
});

let expectedResult = Buffer.from('FF0040075AF0750700FE9145DC00FDFF00BBFD1934', 'hex');
expect(Buffer.from(stream)).to.deep.equal(expectedResult);
});

});
93 changes: 93 additions & 0 deletions lib/varint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
class VarInt {
constructor(valueOrBuf, offset = 0) {
if (typeof valueOrBuf === 'number' || typeof valueOrBuf === 'bigint') {
this.value = BigInt.asUintN(64, BigInt(valueOrBuf)); // Ensure value is treated as unsigned 64-bit integer
this.originallyEncodedSize = this.getSizeInBytes();
} else if (valueOrBuf instanceof Uint8Array) {
const buf = valueOrBuf;
const first = buf[offset] & 0xFF;
if (first < 253) {
this.value = BigInt(first);
this.originallyEncodedSize = 1;
} else if (first === 253) {
this.value = BigInt((buf[offset + 1] & 0xFF) | ((buf[offset + 2] & 0xFF) << 8));
this.originallyEncodedSize = 3;
} else if (first === 254) {
this.value = Utils.readUint32(buf, offset + 1);
this.originallyEncodedSize = 5;
} else {
this.value = Utils.readInt64(buf, offset + 1);
this.originallyEncodedSize = 9;
}
} else {
throw new Error('Invalid constructor argument');
}
}

getOriginalSizeInBytes() {
return this.originallyEncodedSize;
}

getSizeInBytes() {
return VarInt.sizeOf(this.value);
}

static sizeOf(value) {
if (value < 0) return 9; // 1 marker + 8 data bytes
if (value < 253) return 1; // 1 data byte
if (value <= 0xFFFFn) return 3; // 1 marker + 2 data bytes
if (value <= 0xFFFFFFFFn) return 5; // 1 marker + 4 data bytes
return 9; // 1 marker + 8 data bytes
}

encode() {
let bytes;
switch (VarInt.sizeOf(this.value)) {
case 1:
return new Uint8Array([Number(this.value)]);
case 3:
return new Uint8Array([253, Number(this.value) & 0xFF, (Number(this.value) >> 8) & 0xFF]);
case 5:
bytes = new Uint8Array(5);
bytes[0] = 254;
Utils.uint32ToByteArrayLE(this.value, bytes, 1);
return bytes;
default:
bytes = new Uint8Array(9);
bytes[0] = 255;
Utils.uint64ToByteArrayLE(this.value, bytes, 1);
return bytes;
}
}
}

class Utils {
static readUint32(buf, offset) {
return BigInt((buf[offset] & 0xFF) |
((buf[offset + 1] & 0xFF) << 8) |
((buf[offset + 2] & 0xFF) << 16) |
((buf[offset + 3] & 0xFF) << 24) >>> 0);
}

static readInt64(buf, offset) {
let low = Utils.readUint32(buf, offset);
let high = Utils.readUint32(buf, offset + 4);
return (high << 32n) + low;
}

static uint32ToByteArrayLE(value, buf, offset) {
value = BigInt(value);
buf[offset] = Number(value & 0xFFn);
buf[offset + 1] = Number((value >> 8n) & 0xFFn);
buf[offset + 2] = Number((value >> 16n) & 0xFFn);
buf[offset + 3] = Number((value >> 24n) & 0xFFn);
}

static uint64ToByteArrayLE(value, buf, offset) {
value = BigInt(value);
Utils.uint32ToByteArrayLE(value & 0xFFFFFFFFn, buf, offset);
Utils.uint32ToByteArrayLE(value >> 32n, buf, offset + 4);
}
}

module.exports = { VarInt, Utils };
Loading

0 comments on commit d504205

Please sign in to comment.