mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 20:25:48 +00:00
Support encoding and decoding of NegativeUNL pseudo-transactions (#89)
* Support encoding and decoding of NegativeUNL pseudo-transactions
This commit is contained in:
@@ -40,7 +40,8 @@
|
|||||||
"Check": 67,
|
"Check": 67,
|
||||||
"Nickname": 110,
|
"Nickname": 110,
|
||||||
"Contract": 99,
|
"Contract": 99,
|
||||||
"GeneratorMap": 103
|
"GeneratorMap": 103,
|
||||||
|
"NegativeUNL": 78
|
||||||
},
|
},
|
||||||
"FIELDS": [
|
"FIELDS": [
|
||||||
[
|
[
|
||||||
@@ -1023,6 +1024,36 @@
|
|||||||
"type": "Blob"
|
"type": "Blob"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"UNLModifyValidator",
|
||||||
|
{
|
||||||
|
"nth": 19,
|
||||||
|
"isVLEncoded": true,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Blob"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ValidatorToDisable",
|
||||||
|
{
|
||||||
|
"nth": 20,
|
||||||
|
"isVLEncoded": true,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Blob"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ValidatorToReEnable",
|
||||||
|
{
|
||||||
|
"nth": 20,
|
||||||
|
"isVLEncoded": true,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Blob"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Account",
|
"Account",
|
||||||
{
|
{
|
||||||
@@ -1233,6 +1264,16 @@
|
|||||||
"type": "STObject"
|
"type": "STObject"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"DisabledValidator",
|
||||||
|
{
|
||||||
|
"nth": 19,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STObject"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"ArrayEndMarker",
|
"ArrayEndMarker",
|
||||||
{
|
{
|
||||||
@@ -1323,6 +1364,16 @@
|
|||||||
"type": "STArray"
|
"type": "STArray"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"DisabledValidators",
|
||||||
|
{
|
||||||
|
"nth": 17,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "STArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"CloseResolution",
|
"CloseResolution",
|
||||||
{
|
{
|
||||||
@@ -1483,6 +1534,16 @@
|
|||||||
"type": "UInt32"
|
"type": "UInt32"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"BeginLedgerSeq",
|
||||||
|
{
|
||||||
|
"nth": 40,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt32"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Channel",
|
"Channel",
|
||||||
{
|
{
|
||||||
@@ -1523,6 +1584,16 @@
|
|||||||
"type": "UInt8"
|
"type": "UInt8"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"UNLModifyDisabling",
|
||||||
|
{
|
||||||
|
"nth": 17,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt8"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"DestinationNode",
|
"DestinationNode",
|
||||||
{
|
{
|
||||||
@@ -1685,6 +1756,7 @@
|
|||||||
"AccountDelete": 21,
|
"AccountDelete": 21,
|
||||||
|
|
||||||
"EnableAmendment": 100,
|
"EnableAmendment": 100,
|
||||||
"SetFee": 101
|
"SetFee": 101,
|
||||||
|
"UNLModify": 102
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Hash160 } from "./hash-160";
|
|||||||
class AccountID extends Hash160 {
|
class AccountID extends Hash160 {
|
||||||
static readonly defaultAccountID: AccountID = new AccountID(Buffer.alloc(20));
|
static readonly defaultAccountID: AccountID = new AccountID(Buffer.alloc(20));
|
||||||
|
|
||||||
constructor(bytes: Buffer) {
|
constructor(bytes?: Buffer) {
|
||||||
super(bytes ?? AccountID.defaultAccountID.bytes);
|
super(bytes ?? AccountID.defaultAccountID.bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +23,10 @@ class AccountID extends Hash160 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
|
if (value === "") {
|
||||||
|
return new AccountID();
|
||||||
|
}
|
||||||
|
|
||||||
return /^r/.test(value)
|
return /^r/.test(value)
|
||||||
? this.fromBase58(value)
|
? this.fromBase58(value)
|
||||||
: new AccountID(Buffer.from(value, "hex"));
|
: new AccountID(Buffer.from(value, "hex"));
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ class Hash160 extends Hash {
|
|||||||
static readonly width = 20;
|
static readonly width = 20;
|
||||||
static readonly ZERO_160: Hash160 = new Hash160(Buffer.alloc(Hash160.width));
|
static readonly ZERO_160: Hash160 = new Hash160(Buffer.alloc(Hash160.width));
|
||||||
|
|
||||||
constructor(bytes: Buffer) {
|
constructor(bytes?: Buffer) {
|
||||||
|
if (bytes && bytes.byteLength === 0) {
|
||||||
|
bytes = Hash160.ZERO_160.bytes;
|
||||||
|
}
|
||||||
|
|
||||||
super(bytes ?? Hash160.ZERO_160.bytes);
|
super(bytes ?? Hash160.ZERO_160.bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,26 @@ class Hash extends Comparable {
|
|||||||
|
|
||||||
constructor(bytes: Buffer) {
|
constructor(bytes: Buffer) {
|
||||||
super(bytes);
|
super(bytes);
|
||||||
|
if (this.bytes.byteLength !== (this.constructor as typeof Hash).width) {
|
||||||
|
throw new Error(`Invalid Hash length ${this.bytes.byteLength}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a Hash object from an existing Hash object or a hex-string
|
* Construct a Hash object from an existing Hash object or a hex-string
|
||||||
*
|
*
|
||||||
* @param value A hash object or hex-string of a hash
|
* @param value A hash object or hex-string of a hash
|
||||||
*/
|
*/
|
||||||
static from<T extends Hash | string>(value: T): Hash {
|
static from<T extends Hash | string>(value: T): Hash {
|
||||||
if(value instanceof this) {
|
if (value instanceof this) {
|
||||||
return value
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
return new this(Buffer.from(value, "hex"));
|
return new this(Buffer.from(value, "hex"));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Cannot construct Hash from given value");
|
throw new Error("Cannot construct Hash from given value");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ interface HopObject extends JsonObject {
|
|||||||
* TypeGuard for HopObject
|
* TypeGuard for HopObject
|
||||||
*/
|
*/
|
||||||
function isHopObject(arg): arg is HopObject {
|
function isHopObject(arg): arg is HopObject {
|
||||||
return (arg.issuer !== undefined ||
|
return (
|
||||||
arg.account !== undefined ||
|
arg.issuer !== undefined ||
|
||||||
arg.currency !== undefined
|
arg.account !== undefined ||
|
||||||
|
arg.currency !== undefined
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,9 +41,9 @@ function isHopObject(arg): arg is HopObject {
|
|||||||
*/
|
*/
|
||||||
function isPathSet(arg): arg is Array<Array<HopObject>> {
|
function isPathSet(arg): arg is Array<Array<HopObject>> {
|
||||||
return (
|
return (
|
||||||
Array.isArray(arg) && arg.length === 0 ||
|
(Array.isArray(arg) && arg.length === 0) ||
|
||||||
Array.isArray(arg) && Array.isArray(arg[0]) && arg[0].length === 0 ||
|
(Array.isArray(arg) && Array.isArray(arg[0]) && arg[0].length === 0) ||
|
||||||
Array.isArray(arg) && Array.isArray(arg[0]) && isHopObject(arg[0][0])
|
(Array.isArray(arg) && Array.isArray(arg[0]) && isHopObject(arg[0][0]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable func-style */
|
/* eslint-disable func-style */
|
||||||
|
|
||||||
const { binary } = require('../dist/coretypes')
|
const { binary } = require('../dist/coretypes')
|
||||||
const { encode } = require('../dist')
|
const { encode, decode } = require('../dist')
|
||||||
const { makeParser, BytesList, BinarySerializer } = binary
|
const { makeParser, BytesList, BinarySerializer } = binary
|
||||||
const { coreTypes } = require('../dist/types')
|
const { coreTypes } = require('../dist/types')
|
||||||
const { UInt8, UInt16, UInt32, UInt64, STObject } = coreTypes
|
const { UInt8, UInt16, UInt32, UInt64, STObject } = coreTypes
|
||||||
@@ -50,6 +50,8 @@ const PaymentChannel = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NegativeUNL = require('./fixtures/negative-unl.json');
|
||||||
|
|
||||||
function bytesListTest () {
|
function bytesListTest () {
|
||||||
const list = new BytesList().put(Buffer.from([0])).put(Buffer.from([2, 3])).put(Buffer.from([4, 5]))
|
const list = new BytesList().put(Buffer.from([0])).put(Buffer.from([2, 3])).put(Buffer.from([4, 5]))
|
||||||
test('is an Array<Buffer>', function () {
|
test('is an Array<Buffer>', function () {
|
||||||
@@ -171,6 +173,15 @@ function PaymentChannelTest () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NegativeUNLTest () {
|
||||||
|
test('can serialize NegativeUNL', () => {
|
||||||
|
expect(encode(NegativeUNL.tx)).toEqual(NegativeUNL.binary);
|
||||||
|
})
|
||||||
|
test('can deserialize NegativeUNL', () => {
|
||||||
|
expect(decode(NegativeUNL.binary)).toEqual(NegativeUNL.tx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
describe('Binary Serialization', function() {
|
describe('Binary Serialization', function() {
|
||||||
describe('nestedObjectTests', nestedObjectTests);
|
describe('nestedObjectTests', nestedObjectTests);
|
||||||
describe('BytesList', bytesListTest);
|
describe('BytesList', bytesListTest);
|
||||||
@@ -179,4 +190,5 @@ describe('Binary Serialization', function() {
|
|||||||
describe('SignerListSet', SignerListSetTest);
|
describe('SignerListSet', SignerListSetTest);
|
||||||
describe('Escrow', EscrowTest);
|
describe('Escrow', EscrowTest);
|
||||||
describe('PaymentChannel', PaymentChannelTest);
|
describe('PaymentChannel', PaymentChannelTest);
|
||||||
|
describe('NegativeUNLTest', NegativeUNLTest);
|
||||||
})
|
})
|
||||||
12
packages/ripple-binary-codec/test/fixtures/negative-unl.json
vendored
Normal file
12
packages/ripple-binary-codec/test/fixtures/negative-unl.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"binary": "120066240000000026000003006840000000000000007300701321ED9D593004CC501CACD261BD8E31E863F2B3F6CA69505E7FD54DA8F5690BEFB7AE8114000000000000000000000000000000000000000000101101",
|
||||||
|
"tx": {
|
||||||
|
"UNLModifyDisabling": 1,
|
||||||
|
"LedgerSequence": 768,
|
||||||
|
"UNLModifyValidator": "ED9D593004CC501CACD261BD8E31E863F2B3F6CA69505E7FD54DA8F5690BEFB7AE",
|
||||||
|
"TransactionType": "UNLModify",
|
||||||
|
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||||
|
"Sequence": 0,
|
||||||
|
"Fee": "0",
|
||||||
|
"SigningPubKey": ""}
|
||||||
|
}
|
||||||
37
packages/ripple-binary-codec/test/pseudo-transaction.test.js
Normal file
37
packages/ripple-binary-codec/test/pseudo-transaction.test.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const { encode, decode } = require('../dist')
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||||
|
"Sequence": 0,
|
||||||
|
"Fee": "0",
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"Signature": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_blank_acct = {
|
||||||
|
"Account": "",
|
||||||
|
"Sequence": 0,
|
||||||
|
"Fee": "0",
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"Signature": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let binary = "24000000006840000000000000007300760081140000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
describe("Can encode Pseudo Transactions", () => {
|
||||||
|
test("Correctly encodes Pseudo Transaciton", () => {
|
||||||
|
expect(encode(json)).toEqual(binary);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Can decode account objects", () => {
|
||||||
|
expect(decode(encode(json))).toEqual(json);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Blank AccountID is ACCOUNT_ZERO", () => {
|
||||||
|
expect(encode(json_blank_acct)).toEqual(binary)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Decodes Blank AccountID", () => {
|
||||||
|
expect(decode(encode(json_blank_acct))).toEqual(json);
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user