feat: Allow to enable Vrf in testing environments #222

This commit is contained in:
ppe
2022-09-18 23:46:40 +02:00
committed by just_ppe
parent 3c944560b3
commit dfff75118e
5 changed files with 86 additions and 8 deletions

View File

@@ -138,11 +138,43 @@ describe('Testing the Profit Sharing Token', () => {
await expect(pst.readState()).rejects.toThrow('Vrf verification failed.');
useWrongProof.pop();
});
it('should allow to test VRF on a standard forLocal Warp instance', async () => {
const localWarp = WarpFactory.forLocal(1823);
const { contractTxId: vrfContractTxId } = await localWarp.createContract.deploy({
wallet,
initState: JSON.stringify(initialState),
src: contractSrc
});
await mineBlock(localWarp);
const vrfContract = localWarp.contract(vrfContractTxId).connect(wallet);
await vrfContract.writeInteraction(
{
function: 'vrf'
},
{ vrf: true }
);
const result = await vrfContract.readState();
const lastTxId = Object.keys(result.cachedValue.validity).pop();
const vrf = (result.cachedValue.state as any).vrf[lastTxId];
expect(vrf).not.toBeUndefined();
expect(vrf['random_6_1'] == vrf['random_6_2']).toBe(true);
expect(vrf['random_6_2'] == vrf['random_6_3']).toBe(true);
expect(vrf['random_12_1'] == vrf['random_12_2']).toBe(true);
expect(vrf['random_12_2'] == vrf['random_12_3']).toBe(true);
expect(vrf['random_46_1'] == vrf['random_46_2']).toBe(true);
expect(vrf['random_46_2'] == vrf['random_46_3']).toBe(true);
expect(vrf['random_99_1'] == vrf['random_99_2']).toBe(true);
expect(vrf['random_99_2'] == vrf['random_99_3']).toBe(true);
});
});
class VrfDecorator extends ArweaveGatewayInteractionsLoader {
constructor(protected readonly arweave: Arweave) {
super(arweave);
super(arweave, 'local');
}
async load(

View File

@@ -209,7 +209,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
if (!this.signer) {
throw new Error("Wallet not connected. Use 'connect' method first.");
}
const { arweave, interactionsLoader } = this.warp;
const { arweave, interactionsLoader, environment } = this.warp;
const effectiveTags = options?.tags || [];
const effectiveTransfer = options?.transfer || emptyTransfer;
@@ -228,7 +228,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
throw new Error('Ar Transfers are not allowed for bundled interactions');
}
if (effectiveVrf && !bundleInteraction) {
if (effectiveVrf && !bundleInteraction && environment === 'mainnet') {
throw new Error('Vrf generation is only available for bundle interaction');
}
@@ -245,7 +245,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
effectiveTransfer,
effectiveStrict,
false,
false,
effectiveVrf && environment !== 'mainnet',
effectiveReward
);
const response = await arweave.transactions.post(interactionTx);

View File

@@ -73,7 +73,9 @@ export class WarpBuilder {
public useArweaveGateway(): WarpBuilder {
this._definitionLoader = new ContractDefinitionLoader(this._arweave, new MemCache());
this._interactionsLoader = new CacheableInteractionsLoader(new ArweaveGatewayInteractionsLoader(this._arweave));
this._interactionsLoader = new CacheableInteractionsLoader(
new ArweaveGatewayInteractionsLoader(this._arweave, this._environment)
);
return this;
}

View File

@@ -9,11 +9,14 @@ import {
import { Benchmark } from '../../../logging/Benchmark';
import { LoggerFactory } from '../../../logging/LoggerFactory';
import { ArweaveWrapper } from '../../../utils/ArweaveWrapper';
import { sleep } from '../../../utils/utils';
import { bufToBn, sleep } from '../../../utils/utils';
import { GW_TYPE, InteractionsLoader } from '../InteractionsLoader';
import { InteractionsSorter } from '../InteractionsSorter';
import { EvaluationOptions } from '../StateEvaluator';
import { LexicographicalInteractionsSorter } from './LexicographicalInteractionsSorter';
import { WarpEnvironment } from '../../Warp';
import elliptic from 'elliptic';
import { Evaluate } from '@idena/vrf-js';
const MAX_REQUEST = 100;
@@ -38,6 +41,10 @@ export function bundledTxsFilter(tx: GQLEdgeInterface) {
return !tx.node.parent?.id && !tx.node.bundledIn?.id;
}
const EC = new elliptic.ec('secp256k1');
const key = EC.genKeyPair();
const pubKeyS = key.getPublic(true, 'hex');
export class ArweaveGatewayInteractionsLoader implements InteractionsLoader {
private readonly logger = LoggerFactory.INST.create('ArweaveGatewayInteractionsLoader');
@@ -75,7 +82,7 @@ export class ArweaveGatewayInteractionsLoader implements InteractionsLoader {
private readonly arweaveWrapper: ArweaveWrapper;
private readonly sorter: InteractionsSorter;
constructor(protected readonly arweave: Arweave) {
constructor(protected readonly arweave: Arweave, private readonly environment: WarpEnvironment) {
this.arweaveWrapper = new ArweaveWrapper(arweave);
this.sorter = new LexicographicalInteractionsSorter(arweave);
}
@@ -163,7 +170,28 @@ export class ArweaveGatewayInteractionsLoader implements InteractionsLoader {
time: loadingBenchmark.elapsed()
});
return sortedInteractions.map((i) => i.node);
const isLocalOrTestnetEnv = this.environment === 'local' || this.environment === 'testnet';
return sortedInteractions.map((i) => {
const interaction = i.node;
if (isLocalOrTestnetEnv) {
if (
interaction.tags.some((t) => {
return t.name == SmartWeaveTags.REQUEST_VRF && t.value === 'true';
})
) {
const data = this.arweave.utils.stringToBuffer(interaction.sortKey);
const [index, proof] = Evaluate(key.getPrivate().toArray(), data);
interaction.vrf = {
index: this.arweave.utils.bufferTob64Url(index),
proof: this.arweave.utils.bufferTob64Url(proof),
bigint: bufToBn(index).toString(),
pubkey: pubKeyS
};
}
}
return interaction;
});
}
private async loadPages(variables: GqlReqVariables) {

View File

@@ -1,6 +1,7 @@
/* eslint-disable */
import cloneDeep from 'lodash/cloneDeep';
import copy from 'fast-copy';
import { Buffer } from 'redstone-isomorphic';
export const sleep = (ms: number): Promise<void> => {
return new Promise((resolve) => setTimeout(resolve, ms));
@@ -59,3 +60,18 @@ export function stripTrailingSlash(str: string) {
export function indent(callDepth: number) {
return ''.padEnd(callDepth * 2, ' ');
}
export function bufToBn(buf: Buffer) {
const hex = [];
const u8 = Uint8Array.from(buf);
u8.forEach(function (i) {
let h = i.toString(16);
if (h.length % 2) {
h = '0' + h;
}
hex.push(h);
});
return BigInt('0x' + hex.join(''));
}