Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CaminoAddVal] Add nodeOwnerAuth #71

Merged
merged 1 commit into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions e2e_tests/camino/pchain_nomock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const delegationFee: number = 10
const threshold: number = 1
const locktime: BN = new BN(0)
const memo: Buffer = Buffer.from(
"PlatformVM utility method buildAddValidatorTx to add a validator to the primary subnet"
"PlatformVM utility method buildCaminoAddValidatorTx to add a validator to the primary subnet"
)
const interestRateDenominator = new BN(1_000_000 * (365 * 24 * 60 * 60))
const P = function (s: string): string {
Expand Down Expand Up @@ -133,17 +133,20 @@ describe("Camino-PChain-Add-Validator", (): void => {
() =>
(async function () {
const stakeAmount: any = await pChain.getMinStake()
const unsignedTx: UnsignedTx = await pChain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pChain.buildCaminoAddValidatorTx(
undefined,
[P(adminAddress)],
[P(adminAddress)],
[P(adminAddress)],
adminNodeId,
{
address: P(adminAddress),
auth: [[0, P(adminAddress)]]
},
startTime,
endTime,
stakeAmount.minValidatorStake,
[P(adminAddress)],
delegationFee,
locktime,
threshold,
memo
Expand All @@ -161,17 +164,20 @@ describe("Camino-PChain-Add-Validator", (): void => {
() =>
(async function () {
const stakeAmount: any = await pChain.getMinStake()
const unsignedTx: UnsignedTx = await pChain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pChain.buildCaminoAddValidatorTx(
undefined,
[P(adminAddress)],
[P(adminAddress)],
[P(adminAddress)],
node6Id,
{
address: P(adminAddress),
auth: [[0, P(adminAddress)]]
},
startTime,
endTime,
stakeAmount.minValidatorStake,
[P(adminAddress)],
delegationFee,
locktime,
threshold,
memo
Expand Down Expand Up @@ -235,17 +241,20 @@ describe("Camino-PChain-Add-Validator", (): void => {
() =>
(async function () {
const stakeAmount: any = await pChain.getMinStake()
const unsignedTx: UnsignedTx = await pChain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pChain.buildCaminoAddValidatorTx(
undefined,
[P(addrB)], // "X-kopernikus1s93gzmzuvv7gz8q4l83xccrdchh8mtm3xm5s2g"
[P(addrB)],
[P(addrB)],
node6Id,
{
address: P(addrB),
auth: [[0, P(addrB)]]
},
startTime,
endTime,
stakeAmount.minValidatorStake,
[P(addrB)],
delegationFee,
locktime,
threshold,
memo
Expand Down Expand Up @@ -903,17 +912,20 @@ describe("Camino-PChain-Multisig", (): void => {
])
const utxoSet: UTXOSet = platformVMUTXOResponse.utxos

const unsignedTx: UnsignedTx = await pChain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pChain.buildCaminoAddValidatorTx(
utxoSet,
[P(multiSigAliasAddr)],
[[P(multiSigAliasAddr)], [pAddressStrings[5]]],
[P(multiSigAliasAddr)],
node7Id, // the node where the alias is registered
{
address: P(multiSigAliasAddr),
auth: [[0, pAddressStrings[5]]]
},
startTime,
endTime,
new BN(2000000000000),
[P(multiSigAliasAddr)],
0,
undefined,
threshold,
undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,17 +196,20 @@ const sendAddValidatorTx = async (): Promise<any> => {
let startDate = new Date(Date.now() + 0.5 * 60 * 1000).getTime() / 1000
let endDate = startDate + 60 * 60 * 24 * 10

const unsignedTx: UnsignedTx = await pchain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pchain.buildCaminoAddValidatorTx(
utxoSet,
[msigAlias],
[[msigAlias], pAddressStrings],
[msigAlias],
nodeID,
{
address: msigAlias,
auth: [[0, msigAliasArray[0]]]
},
new BN(startDate),
new BN(endDate),
new BN(2000000000000),
[msigAlias],
0, // delegation fee
undefined,
threshold,
undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,20 @@ const sendAddValidatorTx = async (): Promise<any> => {
let startDate = new Date(Date.now() + 0.5 * 60 * 1000).getTime() / 1000
let endDate = startDate + 60 * 60 * 24 * 10

const unsignedTx: UnsignedTx = await pchain.buildAddValidatorTx(
const unsignedTx: UnsignedTx = await pchain.buildCaminoAddValidatorTx(
utxoSet,
[msigAlias],
[[msigAlias], pAddressStrings],
[msigAlias],
nodeID,
{
address: msigAlias,
auth: [[0, msigAliasArray[0]]]
},
new BN(startDate),
new BN(endDate),
new BN(2000000000000),
[msigAlias],
0, // delegation fee
undefined,
threshold,
undefined,
Expand Down
129 changes: 125 additions & 4 deletions src/apis/platformvm/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ import { TransferableInput } from "./inputs"
import { TransferableOutput } from "./outputs"
import { Serialization, SerializedType } from "../../utils"
import { GenesisData } from "../avm"
import { Auth, LockMode, Builder, FromSigner } from "./builder"
import { Auth, LockMode, Builder, FromSigner, NodeOwner } from "./builder"
import { Network } from "../../utils/networks"
import { Spender } from "./spender"

Expand All @@ -100,6 +100,10 @@ const NanoBN = new BN(1000000000)
const rewardPercentDenom = 1000000

type FromType = String[] | String[][]
type NodeOwnerType = {
address: string
auth: [number, string][]
}

/**
* Class for interacting with a node's PlatformVMAPI
Expand Down Expand Up @@ -2007,7 +2011,7 @@ export class PlatformVMAPI extends JRPCAPI {
const minStake: BN = (await this.getMinStake())["minValidatorStake"]
if (stakeAmount.lt(minStake)) {
throw new StakeError(
"PlatformVMAPI.buildAddValidatorTx -- stake amount must be at least " +
`PlatformVMAPI.${caller} -- stake amount must be at least ` +
minStake.toString(10)
)
}
Expand All @@ -2018,7 +2022,7 @@ export class PlatformVMAPI extends JRPCAPI {
delegationFee < 0
) {
throw new DelegationFeeError(
"PlatformVMAPI.buildAddValidatorTx -- delegationFee must be a number between 0 and 100"
`PlatformVMAPI.${caller} -- delegationFee must be a number between 0 and 100`
)
}

Expand All @@ -2027,7 +2031,7 @@ export class PlatformVMAPI extends JRPCAPI {
const now: BN = UnixNow()
if (startTime.lt(now) || endTime.lte(startTime)) {
throw new TimeError(
"PlatformVMAPI.buildAddValidatorTx -- startTime must be in the future and endTime must come after startTime"
`PlatformVMAPI.${caller} -- startTime must be in the future and endTime must come after startTime`
)
}

Expand Down Expand Up @@ -2213,6 +2217,123 @@ export class PlatformVMAPI extends JRPCAPI {

return builtUnsignedTx
}

/**
* Helper function which creates an unsigned [[CaminoAddValidatorTx]]. For more granular control, you may create your own
* [[UnsignedTx]] manually and import the [[CaminoAddValidatorTx]] class directly.
*
* @param utxoset A set of UTXOs that the transaction is built on
* @param toAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who received the staked tokens at the end of the staking period
* @param fromAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who own the staking UTXOs the fees in AVAX
* @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover from the fee payment
* @param nodeID The node ID of the validator being added.
* @param nodeOwner The address and signature indices of the registered nodeId owner.
* @param startTime The Unix time when the validator starts validating the Primary Network.
* @param endTime The Unix time when the validator stops validating the Primary Network (and staked AVAX is returned).
* @param stakeAmount The amount being delegated as a {@link https://github.com/indutny/bn.js/|BN}
* @param rewardAddresses The addresses which will recieve the rewards from the delegated stake.
* @param rewardLocktime Optional. The locktime field created in the resulting reward outputs
* @param rewardThreshold Opional. The number of signatures required to spend the funds in the resultant reward UTXO. Default 1.
* @param memo Optional contains arbitrary bytes, up to 256 bytes
* @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN}
* @param toThreshold Optional. The number of signatures required to spend the funds in the resultant UTXO
* @param changeThreshold Optional. The number of signatures required to spend the funds in the resultant change UTXO
*
* @returns An unsigned transaction created from the passed in parameters.
*/
buildCaminoAddValidatorTx = async (
utxoset: UTXOSet,
toAddresses: string[],
fromAddresses: FromType,
changeAddresses: string[],
nodeID: string,
nodeOwner: NodeOwnerType,
startTime: BN,
endTime: BN,
stakeAmount: BN,
rewardAddresses: string[],
rewardLocktime: BN = ZeroBN,
rewardThreshold: number = 1,
memo: PayloadBase | Buffer = undefined,
asOf: BN = ZeroBN,
toThreshold: number = 1,
changeThreshold: number = 1
): Promise<UnsignedTx> => {
const caller = "buildCaminoAddValidatorTx"

const to: Buffer[] = this._cleanAddressArrayBuffer(toAddresses, caller)

const fromSigner = this._parseFromSigner(fromAddresses, caller)

const change: Buffer[] = this._cleanAddressArrayBuffer(
changeAddresses,
caller
)
const rewards: Buffer[] = this._cleanAddressArrayBuffer(
rewardAddresses,
caller
)

if (memo instanceof PayloadBase) {
memo = memo.getPayload()
}

const minStake: BN = (await this.getMinStake())["minValidatorStake"]
if (stakeAmount.lt(minStake)) {
throw new StakeError(
`PlatformVMAPI.${caller} -- stake amount must be at least ` +
minStake.toString(10)
)
}

const avaxAssetID: Buffer = await this.getAVAXAssetID()

const now: BN = UnixNow()
if (startTime.lt(now) || endTime.lte(startTime)) {
throw new TimeError(
`PlatformVMAPI.${caller} -- startTime must be in the future and endTime must come after startTime`
)
}

const auth: NodeOwner = {
address: this.parseAddress(nodeOwner.address),
auth: []
}
nodeOwner.auth.forEach((o) => {
auth.auth.push([o[0], this.parseAddress(o[1])])
})

const builtUnsignedTx: UnsignedTx = await this._getBuilder(
utxoset
).buildCaminoAddValidatorTx(
this.core.getNetworkID(),
bintools.cb58Decode(this.blockchainID),
to,
fromSigner,
change,
NodeIDStringToBuffer(nodeID),
auth,
startTime,
endTime,
stakeAmount,
avaxAssetID,
rewards,
rewardLocktime,
rewardThreshold,
memo,
asOf,
toThreshold,
changeThreshold
)

if (!(await this.checkGooseEgg(builtUnsignedTx))) {
/* istanbul ignore next */
throw new GooseEggCheckError("Failed Goose Egg Check")
}

return builtUnsignedTx
}

/**
* Build an unsigned [[AddressStateTx]].
*
Expand Down
32 changes: 13 additions & 19 deletions src/apis/platformvm/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ export type FromSigner = {
signer: Buffer[]
}

export type NodeOwner = {
address: Buffer
auth: [number, Buffer][]
}

export type Auth = {
addresses: Buffer[]
threshold: number
Expand Down Expand Up @@ -741,25 +746,7 @@ export class Builder {
changeThreshold: number = 1
): Promise<UnsignedTx> => {
if (this.caminoEnabled) {
return this.buildCaminoAddValidatorTx(
networkID,
blockchainID,
toAddresses,
fromSigner,
changeAddresses,
nodeID,
startTime,
endTime,
stakeAmount,
stakeAssetID,
rewardAddresses,
rewardLocktime,
rewardThreshold,
memo,
asOf,
toThreshold,
changeThreshold
)
throw new Error("Use buildCaminoAddValidatorTx")
}

let ins: TransferableInput[] = []
Expand Down Expand Up @@ -1018,6 +1005,7 @@ export class Builder {
* @param fromSigner The addresses being used to send and verify the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer}
* @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover from the fee payment
* @param nodeID The node ID of the validator being added.
* @param nodeOwner The address and signature indices of the registered nodeId owner.
* @param startTime The Unix time when the validator starts validating the Primary Network.
* @param endTime The Unix time when the validator stops validating the Primary Network (and staked AVAX is returned).
* @param stakeAmount The amount being delegated as a {@link https://github.com/indutny/bn.js/|BN}
Expand All @@ -1038,6 +1026,7 @@ export class Builder {
fromSigner: FromSigner,
change: Buffer[],
nodeID: Buffer,
nodeOwner: NodeOwner,
startTime: BN,
endTime: BN,
stakeAmount: BN,
Expand Down Expand Up @@ -1105,6 +1094,11 @@ export class Builder {
new ParseableOutput(rewardOutputOwners)
)

nodeOwner.auth.forEach((o) => {
baseTx.addSignatureIdx(o[0], o[1])
})
owners.push(new OutputOwners([nodeOwner.address], ZeroBN, 1))

baseTx.setOutputOwners(owners)
return new UnsignedTx(baseTx)
}
Expand Down
Loading