Skip to content

Commit

Permalink
Merge pull request #1107 from ethereum/staging
Browse files Browse the repository at this point in the history
Quick Release
  • Loading branch information
kuzdogan authored Jul 12, 2023
2 parents c4609a3 + 7d34517 commit 7fe95a0
Show file tree
Hide file tree
Showing 18 changed files with 421 additions and 259 deletions.
4 changes: 2 additions & 2 deletions environments/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ SERVER_URL=https://staging.sourcify.dev/server

# Custom nodes
NODE_URL_MAINNET=
NODE_URL_RINKEBY=
NODE_URL_GOERLI=
NODE_URL_SEPOLIA=

CF_ACCESS_CLIENT_ID=
CF_ACCESS_CLIENT_SECRET=

# Other config
TESTING=false
Expand Down
9 changes: 5 additions & 4 deletions environments/.env.latest
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ IPFS_API_EXTERNAL_PORT=5002
SERVER_URL=https://staging.sourcify.dev/server

# Custom nodes
NODE_URL_MAINNET=http://10.10.42.102:8541
NODE_URL_RINKEBY=http://10.10.42.102:8544
NODE_URL_GOERLI=http://10.10.42.102:8545
NODE_URL_SEPOLIA=http://10.10.42.102:8546
NODE_URL_MAINNET=https://rpc.mainnet.ethpandaops.io
NODE_URL_GOERLI=https://rpc.goerli.ethpandaops.io
NODE_URL_SEPOLIA=https://rpc.sepolia.ethpandaops.io
CF_ACCESS_CLIENT_ID=xxx
CF_ACCESS_CLIENT_SECRET=xxx

# Other config
TESTING=false
Expand Down
Binary file modified environments/.env.secrets.gpg
Binary file not shown.
10 changes: 5 additions & 5 deletions environments/.env.stable
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ IPFS_API_EXTERNAL_PORT=5003
SERVER_URL=https://sourcify.dev/server

# Custom nodes
NODE_URL_MAINNET=http://10.10.42.102:8541
NODE_URL_RINKEBY=http://10.10.42.102:8544
NODE_URL_GOERLI=http://10.10.42.102:8545
NODE_URL_SEPOLIA=http://10.10.42.102:8546

NODE_URL_MAINNET=https://rpc.mainnet.ethpandaops.io
NODE_URL_GOERLI=https://rpc.goerli.ethpandaops.io
NODE_URL_SEPOLIA=https://rpc.sepolia.ethpandaops.io
CF_ACCESS_CLIENT_ID=xxx
CF_ACCESS_CLIENT_SECRET=xxx

# Other config
TESTING=false
Expand Down
1 change: 1 addition & 0 deletions packages/lib-sourcify/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { setLogger, setLevel, ILogger } from './lib/logger';
export * from './lib/validation';
export * from './lib/verification';
export * from './lib/CheckedContract';
export { default as SourcifyChain } from './lib/SourcifyChain';
export * from './lib/types';
export * from './lib/solidityCompiler';
export const setLibSourcifyLogger = setLogger;
Expand Down
8 changes: 7 additions & 1 deletion packages/lib-sourcify/src/lib/CheckedContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,13 @@ export class CheckedContract {
async tryToFindPerfectMetadata(
deployedBytecode: string
): Promise<CheckedContract | null> {
const decodedAuxdata = decodeBytecode(deployedBytecode);
let decodedAuxdata;
try {
decodedAuxdata = decodeBytecode(deployedBytecode);
} catch (err) {
// There is no auxdata at all in this contract
return null;
}

const pathContent: PathContent[] = Object.keys(this.solidity).map(
(path) => {
Expand Down
243 changes: 243 additions & 0 deletions packages/lib-sourcify/src/lib/SourcifyChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import {
FetchRequest,
JsonRpcProvider,
Network,
TransactionResponse,
getAddress,
} from 'ethers';
import { Chain, SourcifyChainExtension } from './types';
import { logInfo, logWarn } from './logger';

const RPC_TIMEOUT = process.env.RPC_TIMEOUT
? parseInt(process.env.RPC_TIMEOUT)
: 5000;

// It is impossible to get the url from the Provider for logging purposes
interface JsonRpcProviderWithUrl extends JsonRpcProvider {
url?: string;
}

// Need to define the rpc property explicitly as when a sourcifyChain is created with {...chain, sourcifyChainExtension}, Typescript throws with "Type '(string | FetchRequest)[]' is not assignable to type 'string[]'." For some reason the Chain.rpc is not getting overwritten by SourcifyChainExtension.rpc
export type SourcifyChainInstance = Omit<Chain, 'rpc'> &
Omit<SourcifyChainExtension, 'rpc'> & { rpc: Array<string | FetchRequest> };

export default class SourcifyChain {
name: string;
title?: string | undefined;
chainId: number;
rpc: Array<string | FetchRequest>;
supported: boolean;
monitored: boolean;
contractFetchAddress?: string | undefined;
graphQLFetchAddress?: string | undefined;
txRegex?: string[] | undefined;
providers: JsonRpcProviderWithUrl[];

constructor(sourcifyChainObj: SourcifyChainInstance) {
this.name = sourcifyChainObj.name;
this.title = sourcifyChainObj.title;
this.chainId = sourcifyChainObj.chainId;
this.rpc = sourcifyChainObj.rpc;
this.supported = sourcifyChainObj.supported;
this.monitored = sourcifyChainObj.monitored;
this.contractFetchAddress = sourcifyChainObj.contractFetchAddress;
this.graphQLFetchAddress = sourcifyChainObj.graphQLFetchAddress;
this.txRegex = sourcifyChainObj.txRegex;
this.providers = [];

if (!this.supported) return; // Don't create providers if chain is not supported

if (!this?.rpc.length)
throw new Error(
'No RPC provider was given for this chain with id ' +
this.chainId +
' and name ' +
this.name
);

for (const rpc of this.rpc) {
let provider: JsonRpcProviderWithUrl | undefined;
const ethersNetwork = new Network(this.name, this.chainId);
if (typeof rpc === 'string') {
if (rpc.startsWith('http')) {
// Use staticNetwork to avoid sending unnecessary eth_chainId requests
provider = new JsonRpcProvider(rpc, ethersNetwork, {
staticNetwork: ethersNetwork,
});
provider.url = rpc;
} else {
// Do not use WebSockets because of not being able to catch errors on websocket initialization. Most networks don't support WebSockets anyway. See https://github.com/ethers-io/ethers.js/discussions/2896
// provider = new WebSocketProvider(rpc);
logInfo(`Won't create a WebSocketProvider for ${rpc}`);
}
} else {
provider = new JsonRpcProvider(rpc, ethersNetwork, {
staticNetwork: ethersNetwork,
});
provider.url = rpc.url;
}
if (provider) {
this.providers.push(provider);
}
}
}

rejectInMs = (ms: number, host?: string) =>
new Promise<never>((_resolve, reject) => {
setTimeout(() => reject(`RPC ${host} took too long to respond`), ms);
});

getTx = async (creatorTxHash: string) => {
// Try sequentially all providers
for (const provider of this.providers) {
try {
// Race the RPC call with a timeout
const tx = await Promise.race([
provider.getTransaction(creatorTxHash),
this.rejectInMs(RPC_TIMEOUT, provider.url),
]);
if (tx instanceof TransactionResponse) {
logInfo(
`Transaction ${creatorTxHash} fetched via ${provider.url} from chain ${this.chainId}`
);
return tx;
} else {
throw new Error(
`Transaction ${creatorTxHash} not found on RPC ${provider.url} and chain ${this.chainId}`
);
}
} catch (err) {
if (err instanceof Error) {
logWarn(
`Can't fetch the transaction ${creatorTxHash} from RPC ${provider.url} and chain ${this.chainId}\n ${err}`
);
continue;
} else {
throw err;
}
}
}
throw new Error(
'None of the RPCs responded fetching tx ' +
creatorTxHash +
' on chain ' +
this.chainId
);
};

/**
* Fetches the contract's deployed bytecode from SourcifyChain's rpc's.
* Tries to fetch sequentially if the first RPC is a local eth node. Fetches in parallel otherwise.
*
* @param {SourcifyChain} sourcifyChain - chain object with rpc's
* @param {string} address - contract address
*/
getBytecode = async (address: string): Promise<string> => {
address = getAddress(address);

// Request sequentially. Custom node is always before ALCHEMY so we don't waste resources if succeeds.
for (const provider of this.providers) {
try {
// Race the RPC call with a timeout
const bytecode = await Promise.race([
provider.getCode(address),
this.rejectInMs(RPC_TIMEOUT, provider.url),
]);
logInfo(
'Bytecode fetched from ' +
provider.url +
' for ' +
address +
' on chain ' +
this.chainId
);
return bytecode;
} catch (err) {
if (err instanceof Error) {
logWarn(
`Can't fetch bytecode from RPC ${provider.url} and chain ${this.chainId}`
);
continue;
} else {
throw err;
}
}
}
throw new Error(
'None of the RPCs responded fetching bytecode for ' +
address +
' on chain ' +
this.chainId
);
};

getBlock = async (blockNumber: number, preFetchTxs = true) => {
// Request sequentially. Custom node is always before ALCHEMY so we don't waste resources if succeeds.
for (const provider of this.providers) {
try {
// Race the RPC call with a timeout
const block = await Promise.race([
provider.getBlock(blockNumber, preFetchTxs),
this.rejectInMs(RPC_TIMEOUT, provider.url),
]);
logInfo(
'Block fetched from ' +
provider.url +
' for ' +
blockNumber +
' on chain ' +
this.chainId
);
return block;
} catch (err) {
if (err instanceof Error) {
logWarn(
`Can't fetch block ${blockNumber} from RPC ${provider.url} and chain ${this.chainId}`
);
continue;
} else {
throw err;
}
}
}
throw new Error(
'None of the RPCs responded fetching block ' +
blockNumber +
' on chain ' +
this.chainId
);
};

getBlockNumber = async () => {
// Request sequentially. Custom node is always before ALCHEMY so we don't waste resources if succeeds.
for (const provider of this.providers) {
try {
// Race the RPC call with a timeout
const block = await Promise.race([
provider.getBlockNumber(),
this.rejectInMs(RPC_TIMEOUT, provider.url),
]);
logInfo(
'Block number fetched from ' +
provider.url +
' on chain ' +
this.chainId
);
return block;
} catch (err) {
if (err instanceof Error) {
logWarn(
`Can't fetch the current block number from RPC ${provider.url} and chain ${this.chainId}`
);
continue;
} else {
throw err;
}
}
}
throw new Error(
'None of the RPCs responded fetching the blocknumber on chain ' +
this.chainId
);
};
}
10 changes: 4 additions & 6 deletions packages/lib-sourcify/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Abi } from 'abitype';

import { FetchRequest } from 'ethers';
import SourcifyChain from './SourcifyChain';
export interface PathBuffer {
path: string;
buffer: Buffer;
Expand Down Expand Up @@ -190,7 +191,7 @@ export type SourcifyChainExtension = {
contractFetchAddress?: string;
graphQLFetchAddress?: string;
txRegex?: string[];
rpc?: string[];
rpc?: Array<string | FetchRequest>;
};

// TODO: Double check against ethereum-lists/chains type
Expand All @@ -202,14 +203,11 @@ export type Chain = {
network?: string;
networkId: number;
nativeCurrency: Currency;
rpc: string[];
rpc: Array<string>;
faucets?: string[];
infoURL?: string;
};

// a type that extends the Chain type
export type SourcifyChain = Chain & SourcifyChainExtension;

export type SourcifyChainMap = {
[chainId: string]: SourcifyChain;
};
Expand Down
Loading

0 comments on commit 7fe95a0

Please sign in to comment.