mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-08-04 13:14:07 +00:00
Get bytes length in storageValue host API
This commit is contained in:
parent
8af7417df6
commit
f186e6410d
@ -6,10 +6,11 @@ import path from 'path';
|
|||||||
import chai, { assert, expect } from 'chai';
|
import chai, { assert, expect } from 'chai';
|
||||||
import spies from 'chai-spies';
|
import spies from 'chai-spies';
|
||||||
import { utils } from 'ethers';
|
import { utils } from 'ethers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
|
||||||
import { getDummyEventData, getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyEventData, getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import abi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
import abi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { createEvent, createBlock, Block, EventData } from './utils';
|
import { createEvent, createBlock, Block, EventData } from './utils';
|
||||||
@ -25,6 +26,7 @@ xdescribe('call handler in mapping code', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
let dummyEventData: EventData;
|
let dummyEventData: EventData;
|
||||||
let dummyGraphData: any;
|
let dummyGraphData: any;
|
||||||
@ -33,6 +35,7 @@ xdescribe('call handler in mapping code', () => {
|
|||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
|
|
||||||
// Create dummy test data.
|
// Create dummy test data.
|
||||||
dummyEventData = await getDummyEventData();
|
dummyEventData = await getDummyEventData();
|
||||||
@ -71,6 +74,7 @@ xdescribe('call handler in mapping code', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress: dummyGraphData.dataSource.address
|
contractAddress: dummyGraphData.dataSource.address
|
||||||
|
@ -7,9 +7,10 @@ import { expect } from 'chai';
|
|||||||
import { utils } from 'ethers';
|
import { utils } from 'ethers';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
|
||||||
@ -18,11 +19,13 @@ describe('crypto host api', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the subgraph example wasm', async () => {
|
it('should load the subgraph example wasm', async () => {
|
||||||
@ -33,6 +36,7 @@ describe('crypto host api', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -9,13 +9,14 @@ import chai from 'chai';
|
|||||||
import spies from 'chai-spies';
|
import spies from 'chai-spies';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { createEvent, Block, createBlock, EventData } from './utils';
|
import { createEvent, Block, createBlock, EventData } from './utils';
|
||||||
import edenNetworkAbi from '../test/subgraph/eden/EdenNetwork/abis/EdenNetwork.json';
|
import edenNetworkAbi from '../test/subgraph/eden/EdenNetwork/abis/EdenNetwork.json';
|
||||||
import merkleDistributorAbi from '../test/subgraph/eden/EdenNetworkDistribution/abis/MerkleDistributor.json';
|
import merkleDistributorAbi from '../test/subgraph/eden/EdenNetworkDistribution/abis/MerkleDistributor.json';
|
||||||
import distributorGovernanceAbi from '../test/subgraph/eden/EdenNetworkGovernance/abis/DistributorGovernance.json';
|
import distributorGovernanceAbi from '../test/subgraph/eden/EdenNetworkGovernance/abis/DistributorGovernance.json';
|
||||||
import { getDummyEventData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyEventData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ xdescribe('eden wasm loader tests', async () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
let dummyEventData: EventData;
|
let dummyEventData: EventData;
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ xdescribe('eden wasm loader tests', async () => {
|
|||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
|
|
||||||
// Create dummy test data.
|
// Create dummy test data.
|
||||||
dummyEventData = await getDummyEventData();
|
dummyEventData = await getDummyEventData();
|
||||||
@ -90,6 +93,7 @@ xdescribe('eden wasm loader tests', async () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress
|
contractAddress
|
||||||
@ -210,6 +214,7 @@ xdescribe('eden wasm loader tests', async () => {
|
|||||||
({ exports } = await instantiate(db,
|
({ exports } = await instantiate(db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress
|
contractAddress
|
||||||
@ -328,6 +333,7 @@ xdescribe('eden wasm loader tests', async () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress
|
contractAddress
|
||||||
|
@ -6,9 +6,10 @@ import path from 'path';
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ describe('ethereum ABI encode decode', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
let encoded: string;
|
let encoded: string;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the subgraph example wasm', async () => {
|
it('should load the subgraph example wasm', async () => {
|
||||||
@ -33,6 +36,7 @@ describe('ethereum ABI encode decode', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -6,10 +6,11 @@ import assert from 'assert';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import exampleAbi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
import exampleAbi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
||||||
import { getTestDatabase, getTestIndexer, getTestProvider, getDummyEventData } from '../test/utils';
|
import { getTestDatabase, getTestIndexer, getTestProvider, getDummyEventData, getTestEthClient } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
import { EventData } from './utils';
|
import { EventData } from './utils';
|
||||||
@ -19,6 +20,7 @@ xdescribe('eth-call wasm tests', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
const contractAddress = process.env.EXAMPLE_CONTRACT_ADDRESS;
|
const contractAddress = process.env.EXAMPLE_CONTRACT_ADDRESS;
|
||||||
assert(contractAddress);
|
assert(contractAddress);
|
||||||
@ -40,6 +42,7 @@ xdescribe('eth-call wasm tests', () => {
|
|||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
|
|
||||||
// Create dummy test data.
|
// Create dummy test data.
|
||||||
dummyEventData = await getDummyEventData();
|
dummyEventData = await getDummyEventData();
|
||||||
@ -51,6 +54,7 @@ xdescribe('eth-call wasm tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress
|
contractAddress
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
|
||||||
@ -16,11 +17,13 @@ describe('json host api', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the subgraph example wasm', async () => {
|
it('should load the subgraph example wasm', async () => {
|
||||||
@ -31,6 +34,7 @@ describe('json host api', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -9,9 +9,10 @@ import { utils } from 'ethers';
|
|||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
const WASM_FILE_PATH = '../build/debug.wasm';
|
const WASM_FILE_PATH = '../build/debug.wasm';
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ describe('wasm loader tests', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
let module: WebAssembly.Module;
|
let module: WebAssembly.Module;
|
||||||
let dummyGraphData: any;
|
let dummyGraphData: any;
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ describe('wasm loader tests', () => {
|
|||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
dummyGraphData = getDummyGraphData();
|
dummyGraphData = getDummyGraphData();
|
||||||
|
|
||||||
const filePath = path.resolve(__dirname, WASM_FILE_PATH);
|
const filePath = path.resolve(__dirname, WASM_FILE_PATH);
|
||||||
@ -35,6 +38,7 @@ describe('wasm loader tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
@ -113,6 +117,7 @@ describe('wasm loader tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
module,
|
module,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -16,6 +16,8 @@ import debug from 'debug';
|
|||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
import loader from '@vulcanize/assemblyscript/lib/loader';
|
import loader from '@vulcanize/assemblyscript/lib/loader';
|
||||||
import { IndexerInterface, GraphDecimal, getGraphDigitsAndExp, jsonBigIntStringReplacer } from '@vulcanize/util';
|
import { IndexerInterface, GraphDecimal, getGraphDigitsAndExp, jsonBigIntStringReplacer } from '@vulcanize/util';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
import { getBytesLength, getStorageValue } from '@vulcanize/solidity-mapper';
|
||||||
|
|
||||||
import { TypeId, Level } from './types';
|
import { TypeId, Level } from './types';
|
||||||
import {
|
import {
|
||||||
@ -55,6 +57,7 @@ export const instantiate = async (
|
|||||||
database: Database,
|
database: Database,
|
||||||
indexer: IndexerInterface,
|
indexer: IndexerInterface,
|
||||||
provider: BaseProvider,
|
provider: BaseProvider,
|
||||||
|
ethClient: EthClient,
|
||||||
context: Context,
|
context: Context,
|
||||||
filePathOrModule: string | WebAssembly.Module,
|
filePathOrModule: string | WebAssembly.Module,
|
||||||
data: GraphData
|
data: GraphData
|
||||||
@ -267,7 +270,7 @@ export const instantiate = async (
|
|||||||
|
|
||||||
return toEthereumValue(instanceExports, utils.ParamType.from(typesString), decoded);
|
return toEthereumValue(instanceExports, utils.ParamType.from(typesString), decoded);
|
||||||
},
|
},
|
||||||
'ethereum.storageValue': async (variable: number, mappingKeys: number) => {
|
'ethereum.storageValue': async (variable: number, mappingKeys: number, bytesLength: number) => {
|
||||||
assert(context.contractAddress);
|
assert(context.contractAddress);
|
||||||
const addressStringPtr = await __newString(context.contractAddress);
|
const addressStringPtr = await __newString(context.contractAddress);
|
||||||
const addressString = __getString(addressStringPtr);
|
const addressString = __getString(addressStringPtr);
|
||||||
@ -284,23 +287,39 @@ export const instantiate = async (
|
|||||||
const storageLayout = indexer.storageLayoutMap.get(dataSource.name);
|
const storageLayout = indexer.storageLayoutMap.get(dataSource.name);
|
||||||
assert(storageLayout);
|
assert(storageLayout);
|
||||||
assert(context.block);
|
assert(context.block);
|
||||||
|
let value: any;
|
||||||
|
|
||||||
console.time(`time:loader#ethereum.storageValue-${variableString}`);
|
console.time(`time:loader#ethereum.storageValue-${variableString}`);
|
||||||
const result = await indexer.getStorageValue(
|
if (bytesLength) {
|
||||||
storageLayout,
|
value = await getBytesLength(
|
||||||
context.block.blockHash,
|
storageLayout,
|
||||||
addressString,
|
ethClient.getStorageAt.bind(ethClient),
|
||||||
variableString,
|
context.block.blockHash,
|
||||||
...mappingKeyValues
|
addressString,
|
||||||
);
|
variableString
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
({ value } = await getStorageValue(
|
||||||
|
storageLayout,
|
||||||
|
ethClient.getStorageAt.bind(ethClient),
|
||||||
|
context.block.blockHash,
|
||||||
|
addressString,
|
||||||
|
variableString,
|
||||||
|
...mappingKeyValues
|
||||||
|
));
|
||||||
|
}
|
||||||
console.timeEnd(`time:loader#ethereum.storageValue-${variableString}`);
|
console.timeEnd(`time:loader#ethereum.storageValue-${variableString}`);
|
||||||
|
|
||||||
const storageValueType = getStorageValueType(storageLayout, variableString, mappingKeyValues);
|
let storageValueType = getStorageValueType(storageLayout, variableString, mappingKeyValues);
|
||||||
|
|
||||||
|
if (bytesLength) {
|
||||||
|
storageValueType = utils.ParamType.from('uint');
|
||||||
|
}
|
||||||
|
|
||||||
return toEthereumValue(
|
return toEthereumValue(
|
||||||
instanceExports,
|
instanceExports,
|
||||||
storageValueType,
|
storageValueType,
|
||||||
result.value
|
value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -8,6 +8,7 @@ import BN from 'bn.js';
|
|||||||
|
|
||||||
import { GraphDecimal } from '@vulcanize/util';
|
import { GraphDecimal } from '@vulcanize/util';
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
@ -31,6 +32,7 @@ describe('numbers wasm tests', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
@ -44,6 +46,7 @@ describe('numbers wasm tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -6,11 +6,12 @@ import assert from 'assert';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import exampleAbi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
import exampleAbi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
|
||||||
import { storageLayout } from '../test/artifacts/Example1.json';
|
import { storageLayout } from '../test/artifacts/Example1.json';
|
||||||
import { getTestDatabase, getTestIndexer, getTestProvider, getDummyEventData } from '../test/utils';
|
import { getTestDatabase, getTestIndexer, getTestProvider, getDummyEventData, getTestEthClient } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
import { EventData } from './utils';
|
import { EventData } from './utils';
|
||||||
@ -20,6 +21,7 @@ xdescribe('storage-call wasm tests', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
const contractAddress = process.env.EXAMPLE_CONTRACT_ADDRESS;
|
const contractAddress = process.env.EXAMPLE_CONTRACT_ADDRESS;
|
||||||
assert(contractAddress);
|
assert(contractAddress);
|
||||||
@ -41,6 +43,7 @@ xdescribe('storage-call wasm tests', () => {
|
|||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer(new Map([['Example1', storageLayout]]));
|
indexer = getTestIndexer(new Map([['Example1', storageLayout]]));
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
|
|
||||||
// Create dummy test data.
|
// Create dummy test data.
|
||||||
dummyEventData = await getDummyEventData();
|
dummyEventData = await getDummyEventData();
|
||||||
@ -52,6 +55,7 @@ xdescribe('storage-call wasm tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{
|
{
|
||||||
block: dummyEventData.block,
|
block: dummyEventData.block,
|
||||||
contractAddress
|
contractAddress
|
||||||
|
@ -9,9 +9,10 @@ import { utils, BigNumber } from 'ethers';
|
|||||||
import { BaseProvider } from '@ethersproject/providers';
|
import { BaseProvider } from '@ethersproject/providers';
|
||||||
|
|
||||||
import { instantiate } from './loader';
|
import { instantiate } from './loader';
|
||||||
import { getDummyGraphData, getTestDatabase, getTestIndexer, getTestProvider } from '../test/utils';
|
import { getDummyGraphData, getTestDatabase, getTestEthClient, getTestIndexer, getTestProvider } from '../test/utils';
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Indexer } from '../test/utils/indexer';
|
import { Indexer } from '../test/utils/indexer';
|
||||||
|
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||||
|
|
||||||
const EXAMPLE_WASM_FILE_PATH = '../test/subgraph/example1/build/Example1/Example1.wasm';
|
const EXAMPLE_WASM_FILE_PATH = '../test/subgraph/example1/build/Example1/Example1.wasm';
|
||||||
|
|
||||||
@ -20,11 +21,13 @@ describe('typeConversion wasm tests', () => {
|
|||||||
let db: Database;
|
let db: Database;
|
||||||
let indexer: Indexer;
|
let indexer: Indexer;
|
||||||
let provider: BaseProvider;
|
let provider: BaseProvider;
|
||||||
|
let ethClient: EthClient;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
db = getTestDatabase();
|
db = getTestDatabase();
|
||||||
indexer = getTestIndexer();
|
indexer = getTestIndexer();
|
||||||
provider = getTestProvider();
|
provider = getTestProvider();
|
||||||
|
ethClient = getTestEthClient();
|
||||||
|
|
||||||
const dummyGraphData = getDummyGraphData();
|
const dummyGraphData = getDummyGraphData();
|
||||||
const filePath = path.resolve(__dirname, EXAMPLE_WASM_FILE_PATH);
|
const filePath = path.resolve(__dirname, EXAMPLE_WASM_FILE_PATH);
|
||||||
@ -33,6 +36,7 @@ describe('typeConversion wasm tests', () => {
|
|||||||
db,
|
db,
|
||||||
indexer,
|
indexer,
|
||||||
provider,
|
provider,
|
||||||
|
ethClient,
|
||||||
{},
|
{},
|
||||||
filePath,
|
filePath,
|
||||||
dummyGraphData
|
dummyGraphData
|
||||||
|
@ -78,7 +78,7 @@ export class GraphWatcher {
|
|||||||
assert(this._indexer);
|
assert(this._indexer);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instance: await instantiate(this._database, this._indexer, this._ethProvider, this._context, filePath, data),
|
instance: await instantiate(this._database, this._indexer, this._ethProvider, this._ethClient, this._context, filePath, data),
|
||||||
contractInterface,
|
contractInterface,
|
||||||
data
|
data
|
||||||
};
|
};
|
||||||
@ -315,6 +315,7 @@ export class GraphWatcher {
|
|||||||
this._database,
|
this._database,
|
||||||
this._indexer,
|
this._indexer,
|
||||||
this._ethProvider,
|
this._ethProvider,
|
||||||
|
this._ethClient,
|
||||||
this._context,
|
this._context,
|
||||||
module,
|
module,
|
||||||
data
|
data
|
||||||
|
@ -75,12 +75,7 @@ export const getTestDatabase = (): Database => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getTestIndexer = (storageLayout?: Map<string, StorageLayout>): Indexer => {
|
export const getTestIndexer = (storageLayout?: Map<string, StorageLayout>): Indexer => {
|
||||||
const ethClient = new EthClient({
|
return new Indexer(storageLayout);
|
||||||
gqlEndpoint: IPLD_ETH_SERVER_GQL_URL,
|
|
||||||
cache: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Indexer(ethClient, storageLayout);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTestProvider = (): BaseProvider => {
|
export const getTestProvider = (): BaseProvider => {
|
||||||
@ -88,3 +83,8 @@ export const getTestProvider = (): BaseProvider => {
|
|||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTestEthClient = (): EthClient => new EthClient({
|
||||||
|
gqlEndpoint: IPLD_ETH_SERVER_GQL_URL,
|
||||||
|
cache: undefined
|
||||||
|
});
|
||||||
|
@ -6,19 +6,14 @@ import {
|
|||||||
BlockProgressInterface,
|
BlockProgressInterface,
|
||||||
EventInterface,
|
EventInterface,
|
||||||
SyncStatusInterface,
|
SyncStatusInterface,
|
||||||
ServerConfig as ServerConfigInterface,
|
ServerConfig as ServerConfigInterface
|
||||||
ValueResult
|
|
||||||
} from '@vulcanize/util';
|
} from '@vulcanize/util';
|
||||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
import { StorageLayout } from '@vulcanize/solidity-mapper';
|
||||||
import { GetStorageAt, getStorageValue, MappingKey, StorageLayout } from '@vulcanize/solidity-mapper';
|
|
||||||
|
|
||||||
export class Indexer implements IndexerInterface {
|
export class Indexer implements IndexerInterface {
|
||||||
_getStorageAt: GetStorageAt;
|
|
||||||
_storageLayoutMap: Map<string, StorageLayout> = new Map()
|
_storageLayoutMap: Map<string, StorageLayout> = new Map()
|
||||||
|
|
||||||
constructor (ethClient: EthClient, storageLayoutMap?: Map<string, StorageLayout>) {
|
constructor (storageLayoutMap?: Map<string, StorageLayout>) {
|
||||||
this._getStorageAt = ethClient.getStorageAt.bind(ethClient);
|
|
||||||
|
|
||||||
if (storageLayoutMap) {
|
if (storageLayoutMap) {
|
||||||
this._storageLayoutMap = storageLayoutMap;
|
this._storageLayoutMap = storageLayoutMap;
|
||||||
}
|
}
|
||||||
@ -32,17 +27,6 @@ export class Indexer implements IndexerInterface {
|
|||||||
return this._storageLayoutMap;
|
return this._storageLayoutMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStorageValue (storageLayout: StorageLayout, blockHash: string, contractAddress: string, variable: string, ...mappingKeys: MappingKey[]): Promise<ValueResult> {
|
|
||||||
return getStorageValue(
|
|
||||||
storageLayout,
|
|
||||||
this._getStorageAt,
|
|
||||||
blockHash,
|
|
||||||
contractAddress,
|
|
||||||
variable,
|
|
||||||
...mappingKeys
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlockProgress (blockHash: string): Promise<BlockProgressInterface | undefined> {
|
async getBlockProgress (blockHash: string): Promise<BlockProgressInterface | undefined> {
|
||||||
assert(blockHash);
|
assert(blockHash);
|
||||||
|
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
// Copyright 2021 Vulcanize, Inc.
|
// Copyright 2021 Vulcanize, Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
export { getStorageValue, getStorageInfo, getValueByType, StorageLayout, GetStorageAt, MappingKey } from './storage';
|
export { getStorageValue, getStorageInfo, getValueByType, getBytesLength, StorageLayout, GetStorageAt, MappingKey } from './storage';
|
||||||
|
|
||||||
export { getEventNameTopics } from './logs';
|
export { getEventNameTopics } from './logs';
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Copyright 2021 Vulcanize, Inc.
|
// Copyright 2021 Vulcanize, Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import assert from 'assert';
|
||||||
import { utils, BigNumber } from 'ethers';
|
import { utils, BigNumber } from 'ethers';
|
||||||
|
|
||||||
interface Storage {
|
interface Storage {
|
||||||
@ -108,6 +109,55 @@ export const getValueByType = (storageValue: string, typeLabel: string): bigint
|
|||||||
return storageValue;
|
return storageValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get slot for mapping types.
|
||||||
|
* @param mappingSlot
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
export const getMappingSlot = (types: Types, mappingSlot: string, keyType: string, key: MappingKey): string => {
|
||||||
|
const { encoding, label: typeLabel } = types[keyType];
|
||||||
|
|
||||||
|
// If key is boolean type convert to 1 or 0 which is the way value is stored in memory.
|
||||||
|
if (typeLabel === 'bool') {
|
||||||
|
key = key ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If key is string convert to hex string representation.
|
||||||
|
if (typeLabel === 'string' && typeof key === 'string') {
|
||||||
|
key = utils.hexlify(utils.toUtf8Bytes(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If key is still boolean type the argument passed as key is invalid.
|
||||||
|
if (typeof key === 'boolean') {
|
||||||
|
throw new Error('Invalid key.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/ethers-io/ethers.js/issues/1079#issuecomment-703056242
|
||||||
|
const mappingSlotPadded = utils.hexZeroPad(mappingSlot, 32);
|
||||||
|
|
||||||
|
const keyPadded = encoding === 'bytes'
|
||||||
|
? utils.hexlify(key)
|
||||||
|
: utils.hexZeroPad(utils.hexlify(key), 32);
|
||||||
|
|
||||||
|
// https://docs.soliditylang.org/en/v0.8.4/internals/layout_in_storage.html#mappings-and-dynamic-arrays
|
||||||
|
const fullKey = utils.concat([
|
||||||
|
keyPadded,
|
||||||
|
mappingSlotPadded
|
||||||
|
]);
|
||||||
|
|
||||||
|
const slot = utils.keccak256(fullKey);
|
||||||
|
return slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getBytesLength = async (storageLayout: StorageLayout, getStorageAt: GetStorageAt, blockHash: string, address: string, variableName: string): Promise<number> => {
|
||||||
|
const { slot, type, types } = getStorageInfo(storageLayout, variableName);
|
||||||
|
const { encoding } = types[type];
|
||||||
|
assert(encoding === 'bytes');
|
||||||
|
const { value } = await getStorageAt({ blockHash, contract: address, slot });
|
||||||
|
|
||||||
|
return getBytesLengthFromValue(value);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to get decoded value according to type and encoding.
|
* Function to get decoded value according to type and encoding.
|
||||||
* @param getStorageAt
|
* @param getStorageAt
|
||||||
@ -183,46 +233,6 @@ const getDecodedValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to get slot for mapping types.
|
|
||||||
* @param mappingSlot
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
export const getMappingSlot = (types: Types, mappingSlot: string, keyType: string, key: MappingKey): string => {
|
|
||||||
const { encoding, label: typeLabel } = types[keyType];
|
|
||||||
|
|
||||||
// If key is boolean type convert to 1 or 0 which is the way value is stored in memory.
|
|
||||||
if (typeLabel === 'bool') {
|
|
||||||
key = key ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If key is string convert to hex string representation.
|
|
||||||
if (typeLabel === 'string' && typeof key === 'string') {
|
|
||||||
key = utils.hexlify(utils.toUtf8Bytes(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If key is still boolean type the argument passed as key is invalid.
|
|
||||||
if (typeof key === 'boolean') {
|
|
||||||
throw new Error('Invalid key.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/ethers-io/ethers.js/issues/1079#issuecomment-703056242
|
|
||||||
const mappingSlotPadded = utils.hexZeroPad(mappingSlot, 32);
|
|
||||||
|
|
||||||
const keyPadded = encoding === 'bytes'
|
|
||||||
? utils.hexlify(key)
|
|
||||||
: utils.hexZeroPad(utils.hexlify(key), 32);
|
|
||||||
|
|
||||||
// https://docs.soliditylang.org/en/v0.8.4/internals/layout_in_storage.html#mappings-and-dynamic-arrays
|
|
||||||
const fullKey = utils.concat([
|
|
||||||
keyPadded,
|
|
||||||
mappingSlotPadded
|
|
||||||
]);
|
|
||||||
|
|
||||||
const slot = utils.keccak256(fullKey);
|
|
||||||
return slot;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getDynamicArrayInfo = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string, offset: number, numberOfBytes: string) => {
|
const getDynamicArrayInfo = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string, offset: number, numberOfBytes: string) => {
|
||||||
const { value } = await getInplaceValue(getStorageAt, blockHash, address, slot, offset, numberOfBytes);
|
const { value } = await getInplaceValue(getStorageAt, blockHash, address, slot, offset, numberOfBytes);
|
||||||
const size = Number(getValueByType(value, 'uint'));
|
const size = Number(getValueByType(value, 'uint'));
|
||||||
@ -351,21 +361,9 @@ const getInplaceValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
*/
|
*/
|
||||||
const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string) => {
|
const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string) => {
|
||||||
const { value, proof } = await getStorageAt({ blockHash, contract: address, slot });
|
const { value, proof } = await getStorageAt({ blockHash, contract: address, slot });
|
||||||
let length = 0;
|
const length = getBytesLengthFromValue(value);
|
||||||
const proofs = [JSON.parse(proof.data)];
|
const proofs = [JSON.parse(proof.data)];
|
||||||
|
|
||||||
// Get length of bytes stored.
|
|
||||||
if (BigNumber.from(utils.hexDataSlice(value, 0, 1)).isZero()) {
|
|
||||||
// If first byte is not set, get length directly from the zero padded byte array.
|
|
||||||
const slotValue = BigNumber.from(value);
|
|
||||||
length = slotValue.sub(1).div(2).toNumber();
|
|
||||||
} else {
|
|
||||||
// If first byte is set the length is lesser than 32 bytes.
|
|
||||||
// Length of the value can be computed from the last byte.
|
|
||||||
const lastByteHex = utils.hexDataSlice(value, 31, 32);
|
|
||||||
length = BigNumber.from(lastByteHex).div(2).toNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get value from the byte array directly if length is less than 32.
|
// Get value from the byte array directly if length is less than 32.
|
||||||
if (length < 32) {
|
if (length < 32) {
|
||||||
return {
|
return {
|
||||||
@ -404,3 +402,17 @@ const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, addr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getBytesLengthFromValue = (value: string): number => {
|
||||||
|
// Get length of bytes stored.
|
||||||
|
if (BigNumber.from(utils.hexDataSlice(value, 0, 1)).isZero()) {
|
||||||
|
// If first byte is not set, get length directly from the zero padded byte array.
|
||||||
|
const slotValue = BigNumber.from(value);
|
||||||
|
return slotValue.sub(1).div(2).toNumber();
|
||||||
|
} else {
|
||||||
|
// If first byte is set the length is lesser than 32 bytes.
|
||||||
|
// Length of the value can be computed from the last byte.
|
||||||
|
const lastByteHex = utils.hexDataSlice(value, 31, 32);
|
||||||
|
return BigNumber.from(lastByteHex).div(2).toNumber();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -112,7 +112,6 @@ export interface IndexerInterface {
|
|||||||
processStateCheckpoint?: (contractAddress: string, blockHash: string) => Promise<boolean>
|
processStateCheckpoint?: (contractAddress: string, blockHash: string) => Promise<boolean>
|
||||||
processBlock?: (blockHash: string, blockNumber: number) => Promise<void>
|
processBlock?: (blockHash: string, blockNumber: number) => Promise<void>
|
||||||
processBlockAfterEvents?: (blockHash: string) => Promise<void>
|
processBlockAfterEvents?: (blockHash: string) => Promise<void>
|
||||||
getStorageValue (storageLayout: StorageLayout, blockHash: string, contractAddress: string, variable: string, ...mappingKeys: MappingKey[]): Promise<ValueResult>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPLDIndexerInterface extends IndexerInterface {
|
export interface IPLDIndexerInterface extends IndexerInterface {
|
||||||
|
Loading…
Reference in New Issue
Block a user