fix: update ar gw bundled contracts loader to handle legacy format

This commit is contained in:
Tadeuchi
2023-08-23 11:15:34 +02:00
parent 1ca74e2f7a
commit 05e2542049
3 changed files with 75 additions and 7 deletions

View File

@@ -36,6 +36,7 @@ export const WARP_TAGS = {
WASM_META: 'Wasm-Meta',
REQUEST_VRF: 'Request-Vrf',
SIGNATURE_TYPE: 'Signature-Type',
UPLOADER_TX_ID: 'Uploader-Tx-Id',
WARP_TESTNET: 'Warp-Testnet',
MANIFEST: 'Contract-Manifest',
NONCE: 'Nonce'

View File

@@ -4,6 +4,7 @@ import { ArweaveWrapper } from '../../../utils/ArweaveWrapper';
import { sleep } from '../../../utils/utils';
import { Benchmark } from '../../../logging/Benchmark';
import { Warp } from '../../Warp';
import { WARP_TAGS } from '../../KnownTags';
const TRANSACTIONS_QUERY = `query Transactions($tags: [TagFilter!]!, $blockFilter: BlockFilter!, $first: Int!, $after: String) {
transactions(tags: $tags, block: $blockFilter, first: $first, sort: HEIGHT_ASC, after: $after) {
@@ -56,6 +57,33 @@ const TRANSACTION_QUERY = `query Transaction($id: ID!) {
}
}`;
// this is a query for old/legacy bundler format
const TRANSACTION_QUERY_USING_TAG = `query Transactions($tags: [TagFilter!]!) {
transactions(tags: $tags) {
edges {
node {
id
owner { address, key }
recipient
tags {
name
value
}
block {
height
id
timestamp
}
fee { winston, ar }
quantity { winston, ar }
parent { id }
bundledIn { id }
signature
}
}
}
}`;
interface TagFilter {
name: string;
values: string[];
@@ -93,6 +121,23 @@ export class ArweaveGQLTxsFetcher {
return response.transaction;
}
/**
* Fetches transaction stored using legacy bundling format.
*/
async transactionUsingUploaderTag(transactionId: string): Promise<GQLTransaction> {
const txTag: TagFilter = {
name: WARP_TAGS.UPLOADER_TX_ID,
values: [transactionId]
};
const response = (await this.fetch<GQLResultInterface['data']>(TRANSACTION_QUERY_USING_TAG, { tags: [txTag] }))
.transactions;
if (response.edges.length < 1) {
throw new Error(`No interaction with tag ${WARP_TAGS.UPLOADER_TX_ID}:${transactionId}`);
}
return response.edges[0].node;
}
async transactions(variables: ArweaveTransactionQuery): Promise<GQLEdgeInterface[]> {
let pageResult = (await this.fetch<GQLResultInterface['data']>(TRANSACTIONS_QUERY, variables)).transactions;
const edges: GQLEdgeInterface[] = [...pageResult.edges];

View File

@@ -17,6 +17,7 @@ import { DefinitionLoader } from '../DefinitionLoader';
import { GW_TYPE } from '../InteractionsLoader';
import { ArweaveGQLTxsFetcher } from './ArweaveGQLTxsFetcher';
import { WasmSrc } from './wasm/WasmSrc';
import Arweave from 'arweave';
function getTagValue(tags: GQLTagInterface[], tagName: string, orDefault = undefined) {
const tag = tags.find(({ name }) => name === tagName);
@@ -32,7 +33,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
async load<State>(contractTxId: string, evolvedSrcTxId?: string): Promise<ContractDefinition<State>> {
const benchmark = Benchmark.measure();
const contractTx = await this.arweaveTransactions.transaction(contractTxId);
const contractTx: GQLTransaction = await this.fetchContractTx(contractTxId);
this.logger.debug('Contract tx fetch time', benchmark.elapsed());
const owner = contractTx.owner.address;
@@ -85,6 +86,14 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
return contractDefinition;
}
async fetchContractTx(contractTxId: string): Promise<GQLTransaction | null> {
const txUsingId = await this.arweaveTransactions.transaction(contractTxId);
if (txUsingId == null) {
return await this.arweaveTransactions.transactionUsingUploaderTag(contractTxId);
}
return txUsingId;
}
private async convertToWarpCompatibleContractTx(gqlTransaction: GQLTransaction) {
const tags = gqlTransaction.tags.map(({ name, value }) => ({
name: Buffer.from(name).toString('base64url'),
@@ -103,7 +112,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
async loadContractSource(srcTxId: string): Promise<ContractSource> {
const benchmark = Benchmark.measure();
const contractSrcTx = await this.arweaveTransactions.transaction(srcTxId);
const contractSrcTx = await this.fetchContractTx(srcTxId);
const srcContentType = getTagValue(contractSrcTx.tags, SMART_WEAVE_TAGS.CONTENT_TYPE);
if (!SUPPORTED_SRC_CONTENT_TYPES.includes(srcContentType)) {
@@ -112,10 +121,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
const contractType: ContractType = srcContentType === 'application/javascript' ? 'js' : 'wasm';
const src =
contractType === 'js'
? await this.arweaveWrapper.txDataString(srcTxId)
: await this.arweaveWrapper.txData(srcTxId);
const src = await this.contractSource(contractSrcTx, contractType);
let srcWasmLang: string | undefined;
let wasmSrc: WasmSrc;
@@ -124,7 +130,7 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
wasmSrc = new WasmSrc(src as Buffer);
srcWasmLang = getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_LANG);
if (!srcWasmLang) {
throw new Error(`Wasm lang not set for wasm contract src ${srcTxId}`);
throw new Error(`Wasm lang not set for wasm contract src ${contractSrcTx.id}`);
}
srcMetaData = JSON.parse(getTagValue(contractSrcTx.tags, WARP_TAGS.WASM_META));
}
@@ -142,6 +148,22 @@ export class ArweaveGatewayBundledContractDefinitionLoader implements Definition
};
}
private async contractSource(contractSrcTx: GQLTransaction, contractType: ContractType): Promise<string | Buffer> {
const uploaderId = getTagValue(contractSrcTx.tags, WARP_TAGS.UPLOADER_TX_ID);
if (uploaderId != null) {
const txString = await this.arweaveWrapper.txDataString(contractSrcTx.id);
if (contractType === 'wasm') {
throw new Error('WASM contracts in legacy format are not supported using AR GW');
}
return Arweave.utils.b64UrlToString(JSON.parse(txString).data);
}
return contractType === 'js'
? await this.arweaveWrapper.txDataString(contractSrcTx.id)
: await this.arweaveWrapper.txData(contractSrcTx.id);
}
private async evalInitialState(contractTx: GQLTransaction): Promise<string> {
if (getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE)) {
return getTagValue(contractTx.tags, WARP_TAGS.INIT_STATE);