Skip to content

Commit

Permalink
feat: add p-chain auth complexity
Browse files Browse the repository at this point in the history
  • Loading branch information
erictaylor committed Aug 15, 2024
1 parent bba2054 commit b64d15a
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 6 deletions.
54 changes: 52 additions & 2 deletions src/vms/pvm/txs/fee/complexity.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { utxoId } from '../../../../fixtures/avax';
import { address, id } from '../../../../fixtures/common';
import { bigIntPr, int } from '../../../../fixtures/primitives';
import { bigIntPr, int, ints } from '../../../../fixtures/primitives';
import { signer } from '../../../../fixtures/pvm';
import {
Input,
Expand All @@ -17,6 +17,7 @@ import {
} from '../../../../serializable/pvm';
import { makeDimension } from '../../../common/fees/dimensions';
import {
authComplexity,
inputComplexity,
outputComplexity,
ownerComplexity,
Expand Down Expand Up @@ -185,10 +186,59 @@ describe('Complexity', () => {
144,
0,
0,
// TODO: Implement complexity
// TODO: Implement compute
0,
),
);
});
});

describe('authComplexity', () => {
test('any can spend', () => {
const result = authComplexity(new Input([]));

expect(result).toEqual(
makeDimension(
8,
0,
0,
0, // TODO: Implement
),
);
});

test('one owner', () => {
const result = authComplexity(new Input([int()]));

expect(result).toEqual(
makeDimension(
77,
0,
0,
0, // TODO: Implement
),
);
});

test('three owners', () => {
const result = authComplexity(new Input(ints()));

expect(result).toEqual(
makeDimension(
215,
0,
0,
0, // TODO: Implement
),
);
});

test('invalid auth type', () => {
expect(() => {
authComplexity(int());
}).toThrow(
'Unable to calculate auth complexity of transaction. Expected Input as subnet auth.',
);
});
});
});
56 changes: 52 additions & 4 deletions src/vms/pvm/txs/fee/complexity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
import { SIGNATURE_LENGTH } from '../../../../crypto/secp256k1';
import type { OutputOwners } from '../../../../serializable';
import { NodeId } from '../../../../serializable';
import { Input } from '../../../../serializable/fxs/secp256k1';
import type {
BaseTx,
TransferableInput,
TransferableOutput,
} from '../../../../serializable/avax';
import type {
AddPermissionlessValidatorTx,
AddSubnetValidatorTx,
Signer,
} from '../../../../serializable/pvm';
import { SignerEmpty } from '../../../../serializable/pvm';
Expand All @@ -27,6 +29,7 @@ import {
getEmptyDimensions,
makeDimension,
} from '../../../common/fees/dimensions';
import type { Serializable } from '../../../common/types';

/**
* Number of bytes per long.
Expand Down Expand Up @@ -130,6 +133,17 @@ const INTRINSIC_ADD_PERMISSIONLESS_VALIDATOR_TX_COMPLEXITIES: Dimensions = {
[FeeDimensions.Compute]: 0,
};

const INTRINSIC_ADD_SUBNET_VALIDATOR_TX_COMPLEXITIES: Dimensions = {
[FeeDimensions.Bandwidth]:
INTRINSIC_BASE_TX_COMPLEXITIES[FeeDimensions.Bandwidth] +
INTRINSIC_SUBNET_VALIDATOR_BANDWIDTH + // Subnet Validator
INT_LEN + // Subnet auth typeID
INT_LEN, // Subnet auth credential typeID
[FeeDimensions.DBRead]: 2,
[FeeDimensions.DBWrite]: 1,
[FeeDimensions.Compute]: 0,
};

/**
* Returns the complexity outputs add to a transaction.
*/
Expand Down Expand Up @@ -220,17 +234,42 @@ export const signerComplexity = (signer: Signer | SignerEmpty): Dimensions => {
};

export const ownerComplexity = (owner: OutputOwners): Dimensions => {
const complexity = getEmptyDimensions();

const numberOfAddresses = owner.addrs.length;
const addressBandwidth = numberOfAddresses * SHORT_ID_LEN;

const bandwidth =
addressBandwidth + INTRINSIC_SECP256K1_FX_OUTPUT_OWNERS_BANDWIDTH;

complexity[FeeDimensions.Bandwidth] = bandwidth;
return makeDimension(bandwidth, 0, 0, 0);
};

return complexity;
/**
* Returns the complexity an authorization adds to a transaction.
* It does not include the typeID of the authorization.
* It does include the complexity that the corresponding credential will add.
* It does not include the typeID of the credential.
*/
export const authComplexity = (input: Serializable): Dimensions => {
// TODO: Not a fan of this. May be better to re-type `subnetAuth` as `Input` in `AddSubnetValidatorTx`?
if (!(input instanceof Input)) {
throw new Error(
'Unable to calculate auth complexity of transaction. Expected Input as subnet auth.',
);
}

const numberOfSignatures = input.values().length;

const signatureBandwidth =
numberOfSignatures * INTRINSIC_SECP256K1_FX_SIGNATURE_BANDWIDTH;

const bandwidth = signatureBandwidth + INTRINSIC_SECP256K1_FX_INPUT_BANDWIDTH;

return makeDimension(
bandwidth,
0,
0,
0, // TODO: Add compute complexity.
);
};

// See: vms/platformvm/txs/fee/complexity.go:583
Expand All @@ -251,10 +290,19 @@ export const addPermissionlessValidatorTx = (
tx: AddPermissionlessValidatorTx,
): Dimensions => {
return addDimensions(
INTRINSIC_ADD_PERMISSIONLESS_VALIDATOR_TX_COMPLEXITIES,
baseTxComplexity(tx.baseTx),
signerComplexity(tx.signer),
outputComplexity(tx.stake),
ownerComplexity(tx.getValidatorRewardsOwner()),
ownerComplexity(tx.getDelegatorRewardsOwner()),
);
};

export const addSubnetValidatorTx = (tx: AddSubnetValidatorTx): Dimensions => {
return addDimensions(
INTRINSIC_ADD_SUBNET_VALIDATOR_TX_COMPLEXITIES,
baseTxComplexity(tx.baseTx),
authComplexity(tx.subnetAuth),
);
};

0 comments on commit b64d15a

Please sign in to comment.