commit
7340338626
@ -2,6 +2,10 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.1-rc.4",
|
"version": "1.0.1-rc.4",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Allow for additional properties in txData schema",
|
||||||
|
"pr": 938
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"note": "Change hexSchema to match `0x`",
|
"note": "Change hexSchema to match `0x`",
|
||||||
"pr": 937
|
"pr": 937
|
||||||
|
@ -29,5 +29,4 @@ export const txDataSchema = {
|
|||||||
},
|
},
|
||||||
required: ['from'],
|
required: ['from'],
|
||||||
type: 'object',
|
type: 'object',
|
||||||
additionalProperties: false,
|
|
||||||
};
|
};
|
||||||
|
@ -849,10 +849,6 @@ describe('Schema', () => {
|
|||||||
{
|
{
|
||||||
gas: new BigNumber(42),
|
gas: new BigNumber(42),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
from: NULL_ADDRESS,
|
|
||||||
unknownProp: 'here',
|
|
||||||
},
|
|
||||||
{},
|
{},
|
||||||
[],
|
[],
|
||||||
new BigNumber(1),
|
new BigNumber(1),
|
||||||
|
@ -1,4 +1,28 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Fix a bug when eth_call coverage was not computed because of silent schema validation failures",
|
||||||
|
"pr": 938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Make `TruffleArtifactAdapter` read the `truffle.js` config for `solc` settings",
|
||||||
|
"pr": 938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Change the first param of `TruffleArtifactAdapter` to be the `projectRoot` instead of `sourcesDir`",
|
||||||
|
"pr": 938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Throw a helpful error message if truffle artifacts were generated with a different solc version than the one passed in",
|
||||||
|
"pr": 938
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -1,25 +1,40 @@
|
|||||||
import { Compiler, CompilerOptions } from '@0xproject/sol-compiler';
|
import { Compiler, CompilerOptions } from '@0xproject/sol-compiler';
|
||||||
import * as rimraf from 'rimraf';
|
import * as fs from 'fs';
|
||||||
|
import * as glob from 'glob';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
import { ContractData } from '../types';
|
import { ContractData } from '../types';
|
||||||
|
|
||||||
import { AbstractArtifactAdapter } from './abstract_artifact_adapter';
|
import { AbstractArtifactAdapter } from './abstract_artifact_adapter';
|
||||||
import { SolCompilerArtifactAdapter } from './sol_compiler_artifact_adapter';
|
import { SolCompilerArtifactAdapter } from './sol_compiler_artifact_adapter';
|
||||||
|
|
||||||
|
const DEFAULT_TRUFFLE_ARTIFACTS_DIR = './build/contracts';
|
||||||
|
|
||||||
|
interface TruffleConfig {
|
||||||
|
solc?: any;
|
||||||
|
contracts_build_directory?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class TruffleArtifactAdapter extends AbstractArtifactAdapter {
|
export class TruffleArtifactAdapter extends AbstractArtifactAdapter {
|
||||||
private readonly _solcVersion: string;
|
private readonly _solcVersion: string;
|
||||||
private readonly _sourcesPath: string;
|
private readonly _projectRoot: string;
|
||||||
constructor(sourcesPath: string, solcVersion: string) {
|
constructor(projectRoot: string, solcVersion: string) {
|
||||||
super();
|
super();
|
||||||
this._solcVersion = solcVersion;
|
this._solcVersion = solcVersion;
|
||||||
this._sourcesPath = sourcesPath;
|
this._projectRoot = projectRoot;
|
||||||
}
|
}
|
||||||
public async collectContractsDataAsync(): Promise<ContractData[]> {
|
public async collectContractsDataAsync(): Promise<ContractData[]> {
|
||||||
const artifactsDir = '.0x-artifacts';
|
const artifactsDir = '.0x-artifacts';
|
||||||
|
const contractsDir = path.join(this._projectRoot, 'contracts');
|
||||||
|
const truffleConfig = this._getTruffleConfig();
|
||||||
|
const solcConfig = truffleConfig.solc || {};
|
||||||
|
const truffleArtifactsDirectory = truffleConfig.contracts_build_directory || DEFAULT_TRUFFLE_ARTIFACTS_DIR;
|
||||||
|
this._assertSolidityVersionIsCorrect(truffleArtifactsDirectory);
|
||||||
const compilerOptions: CompilerOptions = {
|
const compilerOptions: CompilerOptions = {
|
||||||
contractsDir: this._sourcesPath,
|
contractsDir,
|
||||||
artifactsDir,
|
artifactsDir,
|
||||||
compilerSettings: {
|
compilerSettings: {
|
||||||
|
...solcConfig,
|
||||||
outputSelection: {
|
outputSelection: {
|
||||||
['*']: {
|
['*']: {
|
||||||
['*']: ['abi', 'evm.bytecode.object', 'evm.deployedBytecode.object'],
|
['*']: ['abi', 'evm.bytecode.object', 'evm.deployedBytecode.object'],
|
||||||
@ -31,9 +46,38 @@ export class TruffleArtifactAdapter extends AbstractArtifactAdapter {
|
|||||||
};
|
};
|
||||||
const compiler = new Compiler(compilerOptions);
|
const compiler = new Compiler(compilerOptions);
|
||||||
await compiler.compileAsync();
|
await compiler.compileAsync();
|
||||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, this._sourcesPath);
|
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter(artifactsDir, contractsDir);
|
||||||
const contractsDataFrom0xArtifacts = await solCompilerArtifactAdapter.collectContractsDataAsync();
|
const contractsDataFrom0xArtifacts = await solCompilerArtifactAdapter.collectContractsDataAsync();
|
||||||
rimraf.sync(artifactsDir);
|
|
||||||
return contractsDataFrom0xArtifacts;
|
return contractsDataFrom0xArtifacts;
|
||||||
}
|
}
|
||||||
|
private _getTruffleConfig(): TruffleConfig {
|
||||||
|
const truffleConfigFileShort = path.resolve(path.join(this._projectRoot, 'truffle.js'));
|
||||||
|
const truffleConfigFileLong = path.resolve(path.join(this._projectRoot, 'truffle-config.js'));
|
||||||
|
if (fs.existsSync(truffleConfigFileShort)) {
|
||||||
|
const truffleConfig = require(truffleConfigFileShort);
|
||||||
|
return truffleConfig;
|
||||||
|
} else if (fs.existsSync(truffleConfigFileLong)) {
|
||||||
|
const truffleConfig = require(truffleConfigFileLong);
|
||||||
|
return truffleConfig;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Neither ${truffleConfigFileShort} nor ${truffleConfigFileLong} exists. Make sure the project root is correct`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _assertSolidityVersionIsCorrect(truffleArtifactsDirectory: string): void {
|
||||||
|
const artifactsGlob = `${truffleArtifactsDirectory}/**/*.json`;
|
||||||
|
const artifactFileNames = glob.sync(artifactsGlob, { absolute: true });
|
||||||
|
for (const artifactFileName of artifactFileNames) {
|
||||||
|
const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
|
||||||
|
const compilerVersion = artifact.compiler.version;
|
||||||
|
if (!compilerVersion.startsWith(this._solcVersion)) {
|
||||||
|
throw new Error(
|
||||||
|
`${artifact.contractName} was compiled with solidity ${compilerVersion} but specified version is ${
|
||||||
|
this._solcVersion
|
||||||
|
} making it impossible for sol-cov to process traces`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import { Callback, ErrorCallback, NextCallback, Subprovider } from '@0xproject/subproviders';
|
import { Callback, ErrorCallback, NextCallback, Subprovider } from '@0xproject/subproviders';
|
||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { CallDataRPC, marshaller, Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import { CallData, JSONRPCRequestPayload, Provider, TxData } from 'ethereum-types';
|
import { JSONRPCRequestPayload, Provider, TxData } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { Lock } from 'semaphore-async-await';
|
import { Lock } from 'semaphore-async-await';
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ export abstract class TraceCollectionSubprovider extends Subprovider {
|
|||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
private async _onCallOrGasEstimateExecutedAsync(
|
private async _onCallOrGasEstimateExecutedAsync(
|
||||||
callData: Partial<CallData>,
|
callData: Partial<CallDataRPC>,
|
||||||
_err: Error | null,
|
_err: Error | null,
|
||||||
_callResult: string,
|
_callResult: string,
|
||||||
cb: Callback,
|
cb: Callback,
|
||||||
@ -160,22 +160,24 @@ export abstract class TraceCollectionSubprovider extends Subprovider {
|
|||||||
await this._recordCallOrGasEstimateTraceAsync(callData);
|
await this._recordCallOrGasEstimateTraceAsync(callData);
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
private async _recordCallOrGasEstimateTraceAsync(callData: Partial<CallData>): Promise<void> {
|
private async _recordCallOrGasEstimateTraceAsync(callData: Partial<CallDataRPC>): Promise<void> {
|
||||||
// We don't want other transactions to be exeucted during snashotting period, that's why we lock the
|
// We don't want other transactions to be exeucted during snashotting period, that's why we lock the
|
||||||
// transaction execution for all transactions except our fake ones.
|
// transaction execution for all transactions except our fake ones.
|
||||||
await this._lock.acquire();
|
await this._lock.acquire();
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(this._web3Wrapper);
|
const blockchainLifecycle = new BlockchainLifecycle(this._web3Wrapper);
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
const fakeTxData: MaybeFakeTxData = {
|
const fakeTxData = {
|
||||||
gas: BLOCK_GAS_LIMIT,
|
gas: BLOCK_GAS_LIMIT.toString(16), // tslint:disable-line:custom-no-magic-numbers
|
||||||
isFakeTransaction: true, // This transaction (and only it) is allowed to come through when the lock is locked
|
isFakeTransaction: true, // This transaction (and only it) is allowed to come through when the lock is locked
|
||||||
...callData,
|
...callData,
|
||||||
from: callData.from || this._defaultFromAddress,
|
from: callData.from || this._defaultFromAddress,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const txHash = await this._web3Wrapper.sendTransactionAsync(fakeTxData);
|
const txData = marshaller.unmarshalTxData(fakeTxData);
|
||||||
|
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
|
||||||
await this._web3Wrapper.awaitTransactionMinedAsync(txHash, 0);
|
await this._web3Wrapper.awaitTransactionMinedAsync(txHash, 0);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// TODO(logvinov) Check that transaction failed and not some other exception
|
||||||
// Even if this transaction failed - we've already recorded it's trace.
|
// Even if this transaction failed - we've already recorded it's trace.
|
||||||
_.noop();
|
_.noop();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
import { marshaller, Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import { marshaller } from '@0xproject/web3-wrapper/lib/src/marshaller';
|
|
||||||
import { JSONRPCRequestPayload, Provider } from 'ethereum-types';
|
import { JSONRPCRequestPayload, Provider } from 'ethereum-types';
|
||||||
|
|
||||||
import { Callback, ErrorCallback } from '../types';
|
import { Callback, ErrorCallback } from '../types';
|
||||||
|
@ -1,4 +1,17 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.2.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Export marshaller to convert between RPC and user-space data formats",
|
||||||
|
"pr": 938
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Export RPC types",
|
||||||
|
"pr": 938
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1532619515,
|
"timestamp": 1532619515,
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
|
@ -1,2 +1,13 @@
|
|||||||
export { Web3Wrapper } from './web3_wrapper';
|
export { Web3Wrapper } from './web3_wrapper';
|
||||||
export { Web3WrapperErrors, NodeType } from './types';
|
export { marshaller } from './marshaller';
|
||||||
|
export {
|
||||||
|
Web3WrapperErrors,
|
||||||
|
NodeType,
|
||||||
|
CallDataRPC,
|
||||||
|
CallTxDataBaseRPC,
|
||||||
|
AbstractBlockRPC,
|
||||||
|
BlockWithoutTransactionDataRPC,
|
||||||
|
BlockWithTransactionDataRPC,
|
||||||
|
TransactionRPC,
|
||||||
|
TxDataRPC,
|
||||||
|
} from './types';
|
||||||
|
@ -25,7 +25,15 @@ import {
|
|||||||
TxDataRPC,
|
TxDataRPC,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utils to convert ethereum structures from user-space format to RPC format. (marshall/unmarshall)
|
||||||
|
*/
|
||||||
export const marshaller = {
|
export const marshaller = {
|
||||||
|
/**
|
||||||
|
* Unmarshall block without transaction data
|
||||||
|
* @param blockWithHexValues block to unmarshall
|
||||||
|
* @return unmarshalled block without transaction data
|
||||||
|
*/
|
||||||
unmarshalIntoBlockWithoutTransactionData(
|
unmarshalIntoBlockWithoutTransactionData(
|
||||||
blockWithHexValues: BlockWithoutTransactionDataRPC,
|
blockWithHexValues: BlockWithoutTransactionDataRPC,
|
||||||
): BlockWithoutTransactionData {
|
): BlockWithoutTransactionData {
|
||||||
@ -41,6 +49,11 @@ export const marshaller = {
|
|||||||
};
|
};
|
||||||
return block;
|
return block;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Unmarshall block with transaction data
|
||||||
|
* @param blockWithHexValues block to unmarshall
|
||||||
|
* @return unmarshalled block with transaction data
|
||||||
|
*/
|
||||||
unmarshalIntoBlockWithTransactionData(blockWithHexValues: BlockWithTransactionDataRPC): BlockWithTransactionData {
|
unmarshalIntoBlockWithTransactionData(blockWithHexValues: BlockWithTransactionDataRPC): BlockWithTransactionData {
|
||||||
const block = {
|
const block = {
|
||||||
...blockWithHexValues,
|
...blockWithHexValues,
|
||||||
@ -59,6 +72,11 @@ export const marshaller = {
|
|||||||
});
|
});
|
||||||
return block;
|
return block;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Unmarshall transaction
|
||||||
|
* @param txRpc transaction to unmarshall
|
||||||
|
* @return unmarshalled transaction
|
||||||
|
*/
|
||||||
unmarshalTransaction(txRpc: TransactionRPC): Transaction {
|
unmarshalTransaction(txRpc: TransactionRPC): Transaction {
|
||||||
const tx = {
|
const tx = {
|
||||||
...txRpc,
|
...txRpc,
|
||||||
@ -73,6 +91,11 @@ export const marshaller = {
|
|||||||
};
|
};
|
||||||
return tx;
|
return tx;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Unmarshall transaction data
|
||||||
|
* @param txDataRpc transaction data to unmarshall
|
||||||
|
* @return unmarshalled transaction data
|
||||||
|
*/
|
||||||
unmarshalTxData(txDataRpc: TxDataRPC): TxData {
|
unmarshalTxData(txDataRpc: TxDataRPC): TxData {
|
||||||
if (_.isUndefined(txDataRpc.from)) {
|
if (_.isUndefined(txDataRpc.from)) {
|
||||||
throw new Error(`txData must include valid 'from' value.`);
|
throw new Error(`txData must include valid 'from' value.`);
|
||||||
@ -86,6 +109,11 @@ export const marshaller = {
|
|||||||
};
|
};
|
||||||
return txData;
|
return txData;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Marshall transaction data
|
||||||
|
* @param txData transaction data to marshall
|
||||||
|
* @return marshalled transaction data
|
||||||
|
*/
|
||||||
marshalTxData(txData: Partial<TxData>): Partial<TxDataRPC> {
|
marshalTxData(txData: Partial<TxData>): Partial<TxDataRPC> {
|
||||||
if (_.isUndefined(txData.from)) {
|
if (_.isUndefined(txData.from)) {
|
||||||
throw new Error(`txData must include valid 'from' value.`);
|
throw new Error(`txData must include valid 'from' value.`);
|
||||||
@ -107,6 +135,11 @@ export const marshaller = {
|
|||||||
});
|
});
|
||||||
return txDataRPC;
|
return txDataRPC;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Marshall call data
|
||||||
|
* @param callData call data to marshall
|
||||||
|
* @return marshalled call data
|
||||||
|
*/
|
||||||
marshalCallData(callData: Partial<CallData>): Partial<CallDataRPC> {
|
marshalCallData(callData: Partial<CallData>): Partial<CallDataRPC> {
|
||||||
const callTxDataBase = {
|
const callTxDataBase = {
|
||||||
...callData,
|
...callData,
|
||||||
@ -119,12 +152,22 @@ export const marshaller = {
|
|||||||
};
|
};
|
||||||
return callDataRPC;
|
return callDataRPC;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Marshall address
|
||||||
|
* @param address address to marshall
|
||||||
|
* @return marshalled address
|
||||||
|
*/
|
||||||
marshalAddress(address: string): string {
|
marshalAddress(address: string): string {
|
||||||
if (addressUtils.isAddress(address)) {
|
if (addressUtils.isAddress(address)) {
|
||||||
return ethUtil.addHexPrefix(address);
|
return ethUtil.addHexPrefix(address);
|
||||||
}
|
}
|
||||||
throw new Error(`Invalid address encountered: ${address}`);
|
throw new Error(`Invalid address encountered: ${address}`);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Marshall block param
|
||||||
|
* @param blockParam block param to marshall
|
||||||
|
* @return marshalled block param
|
||||||
|
*/
|
||||||
marshalBlockParam(blockParam: BlockParam | string | number | undefined): string | undefined {
|
marshalBlockParam(blockParam: BlockParam | string | number | undefined): string | undefined {
|
||||||
if (_.isUndefined(blockParam)) {
|
if (_.isUndefined(blockParam)) {
|
||||||
return BlockParamLiteral.Latest;
|
return BlockParamLiteral.Latest;
|
||||||
@ -132,6 +175,11 @@ export const marshaller = {
|
|||||||
const encodedBlockParam = _.isNumber(blockParam) ? utils.numberToHex(blockParam) : blockParam;
|
const encodedBlockParam = _.isNumber(blockParam) ? utils.numberToHex(blockParam) : blockParam;
|
||||||
return encodedBlockParam;
|
return encodedBlockParam;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Unmarshall log
|
||||||
|
* @param rawLog log to unmarshall
|
||||||
|
* @return unmarshalled log
|
||||||
|
*/
|
||||||
unmarshalLog(rawLog: RawLogEntry): LogEntry {
|
unmarshalLog(rawLog: RawLogEntry): LogEntry {
|
||||||
const formattedLog = {
|
const formattedLog = {
|
||||||
...rawLog,
|
...rawLog,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user