Skip to content

Commit

Permalink
feat: add convertSubnetValidator tests and fix for passing
Browse files Browse the repository at this point in the history
  • Loading branch information
erictaylor committed Oct 22, 2024
1 parent e301e0b commit c69e1e6
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 59 deletions.
52 changes: 37 additions & 15 deletions src/fixtures/pvm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import {
transferableOutputBytes,
} from './avax';
import {
address,
addressBytes,
addresses,
addressesBytes,
id,
idBytes,
nodeId,
Expand Down Expand Up @@ -65,6 +65,7 @@ import { makeList, makeListBytes } from './utils/makeList';
import type { FeeState } from '../vms/pvm';
import { ConvertSubnetTx } from '../serializable/pvm/convertSubnetTx';
import { ConvertSubnetValidator } from '../serializable/fxs/pvm/convertSubnetValidator';
import { PChainOwner } from '../serializable/fxs/pvm/pChainOwner';

export const validator = () =>
new Validator(nodeId(), bigIntPr(), bigIntPr(), bigIntPr());
Expand Down Expand Up @@ -306,33 +307,45 @@ export const transformSubnetTxBytes = () =>

export const convertSubnetValidator = () =>
new ConvertSubnetValidator(
nodeId(),
// nodeId(),
bytes(),
bigIntPr(),
bigIntPr(),
signer(),
outputOwner(),
outputOwner(),

// signer(),
// outputOwner(),
// outputOwner(),
proofOfPossession(),
pChainOwner(),
pChainOwner(),
);

export const convertSubnetValidatorBytes = () =>
concatBytes(
nodeIdBytes(),
// nodeIdBytes(),
bytesBytes(),
bigIntPrBytes(),
bigIntPrBytes(),
bytesForInt(28),
signerBytes(),
bytesForInt(11),
outputOwnerBytes(),
bytesForInt(11),
outputOwnerBytes(),

// bytesForInt(28),
// signerBytes(),
// bytesForInt(11),
// outputOwnerBytes(),
// bytesForInt(11),
// outputOwnerBytes(),

proofOfPossessionBytes(),
pChainOwnerBytes(),
pChainOwnerBytes(),
);

export const convertSubnetTx = () =>
new ConvertSubnetTx(
baseTx(),
id(),
id(),
address(),
// address(),
bytes(),
makeList(convertSubnetValidator)(),
input(),
);
Expand All @@ -342,12 +355,21 @@ export const convertSubnetTxBytes = () =>
baseTxbytes(),
idBytes(),
idBytes(),
addressBytes(),
// addressBytes(),
bytesBytes(),
makeListBytes(convertSubnetValidatorBytes)(),
bytesForInt(10),
inputBytes(),
);

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

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

export const feeState = (): FeeState => ({
capacity: 1n,
excess: 1n,
Expand Down
59 changes: 34 additions & 25 deletions src/serializable/fxs/pvm/convertSubnetValidator.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { pack, unpack } from '../../../utils/struct';
import { Codec } from '../../codec/codec';
import type { Codec } from '../../codec';
import type { Serializable } from '../../common/types';
import { serializable } from '../../common/types';
import { BigIntPr } from '../../primitives';
import { BigIntPr, Bytes } from '../../primitives';
import { TypeSymbols } from '../../constants';
import { emptyNodeId } from '../../../constants/zeroValue';
import { ProofOfPossession } from '../../pvm';
import { NodeId } from '../common';
import { concatBytes } from '@noble/hashes/utils';
import type { SignerEmpty } from '../../pvm';
import type { Signer } from '../../pvm';
import type { OutputOwners } from '../secp256k1';
import { PChainOwner } from './pChainOwner';

/**
* @see https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/txs/convert_subnet_tx.go#86
Expand All @@ -19,36 +16,36 @@ export class ConvertSubnetValidator {
_type = TypeSymbols.ConvertSubnetValidator;

constructor(
public readonly nodeId: NodeId,
public readonly nodeId: Bytes,
public readonly weight: BigIntPr,
public readonly balance: BigIntPr,
public readonly signer: Signer | SignerEmpty,
public readonly signer: ProofOfPossession,
public readonly remainingBalanceOwner: Serializable,
public readonly deactivationOwner: Serializable,
) {}

getBalance() {
return this.balance.value();
return this.balance;
}

getRemainingBalanceOwner() {
return this.remainingBalanceOwner as OutputOwners;
return this.remainingBalanceOwner as PChainOwner;
}

getDeactivationOwner() {
return this.deactivationOwner as OutputOwners;
return this.deactivationOwner as PChainOwner;
}

static fromNative(
nodeId: string,
weight: bigint,
balance: bigint,
signer: Signer | SignerEmpty,
remainingBalanceOwner: OutputOwners,
deactivationOwner: OutputOwners,
signer: ProofOfPossession,
remainingBalanceOwner: PChainOwner,
deactivationOwner: PChainOwner,
) {
return new ConvertSubnetValidator(
NodeId.fromString(nodeId),
new Bytes(NodeId.fromString(nodeId).toBytes()),
new BigIntPr(weight),
new BigIntPr(balance),
signer,
Expand All @@ -69,7 +66,11 @@ export class ConvertSubnetValidator {
remainingBalanceOwner,
deactivationOwner,
rest,
] = unpack(bytes, [NodeId, BigIntPr, BigIntPr, Codec, Codec, Codec], codec);
] = unpack(
bytes,
[Bytes, BigIntPr, BigIntPr, ProofOfPossession, PChainOwner, PChainOwner],
codec,
);

return [
new ConvertSubnetValidator(
Expand All @@ -85,11 +86,16 @@ export class ConvertSubnetValidator {
}

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

Expand All @@ -98,9 +104,12 @@ export class ConvertSubnetValidator {
throw new Error('Weight must be greater than 0');
}

if (this.nodeId === emptyNodeId) {
throw new Error('Node ID must be non-empty');
}
// const nodeId = new NodeId(this.nodeId.toBytesWithoutLength());

// TODO: Properly add this logic back with new types.
// 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.test.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);
45 changes: 45 additions & 0 deletions src/serializable/fxs/pvm/pChainOwner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { concatBytes } from '@noble/hashes/utils';
import { 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[],
) {}

getAddresses() {
return this.addresses;
}

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));
}

static fromNative(addresses: readonly Uint8Array[], threshold = 1) {
return new PChainOwner(
new Int(threshold),
addresses.map((addr) => new Address(addr)),
);
}
}
7 changes: 4 additions & 3 deletions src/serializable/pvm/convertSubnetTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { Codec } from '../codec/codec';
import type { Serializable } from '../common/types';
import { serializable } from '../common/types';
import { TypeSymbols } from '../constants';
import { Address, Id } from '../fxs/common';
import { Id } from '../fxs/common';
import { ConvertSubnetValidator } from '../fxs/pvm/convertSubnetValidator';
import { Bytes } from '../primitives';
import { AbstractSubnetTx } from './abstractSubnetTx';

@serializable()
Expand All @@ -18,7 +19,7 @@ export class ConvertSubnetTx extends AbstractSubnetTx {
public readonly baseTx: BaseTx,
public readonly subnetID: Id,
public readonly chainID: Id,
public readonly address: Address,
public readonly address: Bytes,
public readonly validators: ConvertSubnetValidator[],
public readonly subnetAuth: Serializable,
) {
Expand All @@ -36,7 +37,7 @@ export class ConvertSubnetTx extends AbstractSubnetTx {
const [baseTx, subnetID, chainID, address, validators, subnetAuth, rest] =
unpack(
bytes,
[BaseTx, Id, Id, Address, toListStruct(ConvertSubnetValidator), Codec],
[BaseTx, Id, Id, Bytes, toListStruct(ConvertSubnetValidator), Codec],
codec,
);
return [
Expand Down
6 changes: 3 additions & 3 deletions src/vms/pvm/etna-builder/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
} from '../../../constants/networkIDs';
import type { TransferOutput } from '../../../serializable';
import {
Address,
Input,
NodeId,
OutputOwners,
Expand Down Expand Up @@ -1387,7 +1386,7 @@ export const newConvertSubnetTx: TxBuilderFn<NewConvertSubnetTxProps> = (
for (const validator of sortedValidators) {
toBurn.set(
context.avaxAssetID,
(toBurn.get(context.avaxAssetID) ?? 0n) + validator.getBalance(),
(toBurn.get(context.avaxAssetID) ?? 0n) + validator.getBalance().value(),
);
}

Expand Down Expand Up @@ -1434,7 +1433,8 @@ export const newConvertSubnetTx: TxBuilderFn<NewConvertSubnetTxProps> = (
),
Id.fromString(subnetId),
Id.fromString(chainId),
new Address(address),
// new Address(address),
new Bytes(address),
sortedValidators,
Input.fromNative(subnetAuth),
),
Expand Down
Loading

0 comments on commit c69e1e6

Please sign in to comment.