Skip to content

Commit

Permalink
feat: convertSubtnetTx
Browse files Browse the repository at this point in the history
  • Loading branch information
ruijialin-avalabs committed Oct 15, 2024
1 parent ad65b27 commit d7378fc
Show file tree
Hide file tree
Showing 17 changed files with 516 additions and 12 deletions.
3 changes: 2 additions & 1 deletion src/constants/zeroValue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Id } from '../serializable/fxs/common';
import { Id, NodeId } from '../serializable/fxs/common';
import { OutputOwners } from '../serializable/fxs/secp256k1';
import {
SepkSignatureLength,
Expand All @@ -13,6 +13,7 @@ export const zeroOutputOwners = new OutputOwners(
);

export const emptyId = new Id(new Uint8Array(32));
export const emptyNodeId = new NodeId(new Uint8Array(20));
export const emptySignature = new Signature(
new Uint8Array(Array(SepkSignatureLength).fill(0)),
);
66 changes: 65 additions & 1 deletion src/fixtures/pvm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ import {
transferableOutput,
transferableOutputBytes,
} from './avax';
import { id, idBytes, nodeId, nodeIdBytes } from './common';
import {
address,
addressBytes,
addresses,
addressesBytes,
id,
idBytes,
nodeId,
nodeIdBytes,
} from './common';
import {
bigIntPr,
bigIntPrBytes,
Expand Down Expand Up @@ -56,6 +65,9 @@ import {
import { bytesForInt } from './utils/bytesFor';
import { makeList, makeListBytes } from './utils/makeList';
import type { FeeState } from '../vms/pvm';
import { ConvertSubnetTx } from '../serializable/pvm/convertSubnetTx';
import { PChainOwner } from '../serializable/fxs/pvm/pChainOwner';
import { ConvertSubnetValidator } from '../serializable/fxs/pvm/convertSubnetValidator';

export const validator = () =>
new Validator(nodeId(), bigIntPr(), bigIntPr(), bigIntPr());
Expand Down Expand Up @@ -192,6 +204,9 @@ export const advanceTimeBytesTx = () => bigIntPrBytes();
export const proofOfPossession = () =>
new ProofOfPossession(blsPublicKeyBytes(), blsSignatureBytes());

export const proofOfPossessionBytes = () =>
concatBytes(blsPublicKeyBytes(), blsSignatureBytes());

export const signer = () => new Signer(proofOfPossession());
export const signerBytes = () =>
concatBytes(blsPublicKeyBytes(), blsSignatureBytes());
Expand Down Expand Up @@ -292,6 +307,55 @@ export const transformSubnetTxBytes = () =>
inputBytes(),
);

export const convertSubnetValidator = () =>
new ConvertSubnetValidator(
nodeId(),
bigIntPr(),
bigIntPr(),
proofOfPossession(),
pChainOwner(),
pChainOwner(),
);

export const convertSubnetValidatorBytes = () =>
concatBytes(
nodeIdBytes(),
bigIntPrBytes(),
bigIntPrBytes(),
proofOfPossessionBytes(),
pChainOwnerBytes(),
pChainOwnerBytes(),
);

export const convertSubnetTx = () =>
new ConvertSubnetTx(
baseTx(),
id(),
id(),
address(),
makeList(convertSubnetValidator)(),
input(),
);

export const convertSubnetTxBytes = () =>
concatBytes(
baseTxbytes(),
idBytes(),
idBytes(),
addressBytes(),
makeListBytes(convertSubnetValidatorBytes)(),
inputBytes(),
);

export const pChainOwner = () => new PChainOwner(int(), addresses()());

export const pChainOwnerBytes = () =>
concatBytes(
// threshold:
intBytes(),
addressesBytes(),
);

export const feeState = (): FeeState => ({
capacity: 1n,
excess: 1n,
Expand Down
4 changes: 4 additions & 0 deletions src/fixtures/utils/serializable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export const testSerialization = (

describe(name, () => {
it('serializes correctly', () => {
if (name === 'ConvertSubnetTx') {
console.log('a', entityFixture().toBytes(codec()));
console.log('b', bytesFixture());
}
expect(entityFixture().toBytes(codec())).toStrictEqual(bytesFixture());
});
});
Expand Down
1 change: 1 addition & 0 deletions src/serializable/codec/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class Codec {
UnpackPrefix = <T extends Serializable>(buf: Uint8Array): [T, Uint8Array] => {
let typeId: Int;
[typeId, buf] = unpack(buf, [Int]);
console.log('typeId', typeId, this.typeIdToType);
const type = this.typeIdToType[typeId.value()];

if (type === undefined) {
Expand Down
5 changes: 5 additions & 0 deletions src/serializable/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export enum TypeSymbols {
TransformSubnetTx = 'pvm.TransformSubnetTx',
TransferSubnetOwnershipTx = 'pvm.TransferSubnetOwnershipTx',

ConvertSubnetTx = 'pvm.ConvertSubnetTx',
ConvertSubnetValidator = 'pvm.ConvertSubnetValidator',

PChainOwner = 'pvm.PChainOwner',

// EVM
EvmExportTx = 'evm.ExportTx',
EvmInput = 'evm.Input',
Expand Down
5 changes: 5 additions & 0 deletions src/serializable/fxs/common/nodeId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { hexToBuffer, padLeft } from '../../../utils/buffer';
import { serializable } from '../../common/types';
import { Primitives } from '../../primitives/primatives';
import { TypeSymbols } from '../../constants';
// import { bytesCompare } from '../../../utils';

export const NodeIDPrefix = 'NodeID-';

Expand Down Expand Up @@ -53,4 +54,8 @@ export class NodeId extends Primitives {
value() {
return this.toString();
}

// static compare(id1: NodeId, id2: NodeId): number {
// return bytesCompare(id1.toBytes(), id2.toBytes());
// }
}
86 changes: 86 additions & 0 deletions src/serializable/fxs/pvm/convertSubnetValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { pack, unpack } from '../../../utils/struct';
import type { Codec } from '../../codec/codec';
import { serializable } from '../../common/types';
import { NodeId } from '../common/nodeId';
import { BigIntPr } from '../../primitives';
import { TypeSymbols } from '../../constants';
import { ProofOfPossession } from '../../pvm/proofOfPossession';
import { PChainOwner } from './pChainOwner';
import { emptyNodeId } from '../../../constants/zeroValue';

/**
* @see https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/txs/convert_subnet_tx.go#86
*/
@serializable()
export class ConvertSubnetValidator {
_type = TypeSymbols.ConvertSubnetValidator;

constructor(
public readonly nodeId: NodeId,
public readonly weight: BigIntPr,
public readonly balance: BigIntPr,
public readonly signer: ProofOfPossession,
public readonly remainingBalanceOwner: PChainOwner,
public readonly deactivationOwner: PChainOwner,
) {}

static fromBytes(
bytes: Uint8Array,
codec: Codec,
): [ConvertSubnetValidator, Uint8Array] {
const [
nodeId,
weight,
balance,
signer,
remainingBalanceOwner,
deactivationOwner,
rest,
] = unpack(
bytes,
[NodeId, BigIntPr, BigIntPr, ProofOfPossession, PChainOwner, PChainOwner],
codec,
);

return [
new ConvertSubnetValidator(
nodeId,
weight,
balance,
signer,
remainingBalanceOwner,
deactivationOwner,
),
rest,
];
}

toBytes(codec: Codec) {
return pack(
[
this.nodeId,
this.weight,
this.balance,
this.signer,
this.remainingBalanceOwner,
this.deactivationOwner,
],
codec,
);
}

// static compare(nodeId1: NodeId, nodeId2: NodeId): number {
// return NodeId.compare(nodeId1, nodeId2);
// }

verify(): boolean {
if (this.weight === new BigIntPr(0n)) {
throw new Error('Weight must be greater than 0');
}

if (this.nodeId === emptyNodeId) {
throw new Error('Node ID must be non-empty');
}
return true;
}
}
5 changes: 5 additions & 0 deletions src/serializable/fxs/pvm/pChainOwner.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { pChainOwner, pChainOwnerBytes } from '../../../fixtures/pvm';
import { testSerialization } from '../../../fixtures/utils/serializable';
import { PChainOwner } from './pChainOwner';

testSerialization('PChainOwner', PChainOwner, pChainOwner, pChainOwnerBytes);
37 changes: 37 additions & 0 deletions src/serializable/fxs/pvm/pChainOwner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { concatBytes } from '@noble/hashes/utils';
import { packList, toListStruct } from '../../../utils/serializeList';
import { pack, unpack } from '../../../utils/struct';
import { serializable } from '../../common/types';
import { Int } from '../../primitives';
import { Address } from '../common/address';
import { TypeSymbols } from '../../constants';
import type { Codec } from '../../codec';

/**
* @see https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/message/register_subnet_validator.go
*/
@serializable()
export class PChainOwner {
_type = TypeSymbols.PChainOwner;

constructor(
public readonly threshold: Int,
public readonly addresses: Address[],
) {}

static fromBytes(bytes: Uint8Array, codec: Codec): [PChainOwner, Uint8Array] {
const [threshold, addresses, remaining] = unpack(
bytes,
[Int, toListStruct(Address)],
codec,
);
return [new PChainOwner(threshold, addresses), remaining];
}

toBytes(codec: Codec) {
return concatBytes(
pack([this.threshold, this.addresses], codec),
// packList(this.addresses, codec),
);
}
}
3 changes: 3 additions & 0 deletions src/serializable/pvm/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { RemoveSubnetValidatorTx } from './removeSubnetValidatorTx';
import { TransferSubnetOwnershipTx } from './transferSubnetOwnershipTx';
import { TransformSubnetTx } from './transformSubnetTx';
import { BaseTx } from './baseTx';
import { ConvertSubnetValidator } from '../fxs/pvm/convertSubnetValidator';

/**
* @see https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/txs/codec.go#L35
Expand Down Expand Up @@ -57,6 +58,8 @@ export const codec = new Codec([

TransferSubnetOwnershipTx, // 33
BaseTx, // 34

ConvertSubnetValidator, // 35
]);

let manager: Manager;
Expand Down
12 changes: 12 additions & 0 deletions src/serializable/pvm/convertSubnetTx.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { testPVMCodec } from '../../fixtures/codec';
import { convertSubnetTx, convertSubnetTxBytes } from '../../fixtures/pvm';
import { testSerialization } from '../../fixtures/utils/serializable';
import { ConvertSubnetTx } from './convertSubnetTx';

testSerialization(
'ConvertSubnetTx',
ConvertSubnetTx,
convertSubnetTx,
convertSubnetTxBytes,
testPVMCodec,
);
71 changes: 71 additions & 0 deletions src/serializable/pvm/convertSubnetTx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { concatBytes } from '../../utils/buffer';
import { toListStruct } from '../../utils/serializeList';
import { pack, unpack } from '../../utils/struct';
import { BaseTx } from '../avax/baseTx';
import { Codec } from '../codec/codec';
import type { Serializable } from '../common/types';
import { serializable } from '../common/types';
import { TypeSymbols } from '../constants';
import { Address } from '../fxs/common';
import { Id } from '../fxs/common';
import { ConvertSubnetValidator } from '../fxs/pvm/convertSubnetValidator';
import { AbstractSubnetTx } from './abstractSubnetTx';

@serializable()
export class ConvertSubnetTx extends AbstractSubnetTx {
_type = TypeSymbols.ConvertSubnetTx;

constructor(
public readonly baseTx: BaseTx,
public readonly subnetID: Id,
public readonly chainID: Id,
public readonly address: Address,
public readonly validators: ConvertSubnetValidator[],
public readonly subnetAuth: Serializable,
) {
super();
}

getSubnetID() {
return this.subnetID;
}

static fromBytes(
bytes: Uint8Array,
codec: Codec,
): [ConvertSubnetTx, Uint8Array] {
const [baseTx, subnetID, chainID, address, validators, subnetAuth, rest] =
unpack(
bytes,
[BaseTx, Id, Id, Address, toListStruct(ConvertSubnetValidator), Codec],
codec,
);
return [
new ConvertSubnetTx(
baseTx,
subnetID,
chainID,
address,
validators,
subnetAuth,
),
rest,
];
}

toBytes(codec: Codec) {
return concatBytes(
pack(
[
this.baseTx,
this.subnetID,
this.chainID,
this.address,
this.validators,
],
codec,
),
codec.PackPrefix(this.subnetAuth),
);
}
}
Loading

0 comments on commit d7378fc

Please sign in to comment.