Skip to content

Commit

Permalink
Feat: Add logs requesting, and receipt logs.
Browse files Browse the repository at this point in the history
  • Loading branch information
vldm committed Jan 10, 2021
1 parent 9c81595 commit a91b4f1
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 162 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ docs/node_modules/
docs/build/
explorer/node_modules/
programs/bpf/target/
Dockerfile

local-cluster/farf/
core/farf/
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ COPY ./ /solana
#RUN git clone https://github.com/solana-labs/solana
WORKDIR /solana
RUN cargo build --release
RUN rm /solana/target/release/deps -rf
RUN rm /solana/target/release/build -rf

FROM ubuntu:20.04 as dest
RUN apt-get update && \
Expand Down
2 changes: 2 additions & 0 deletions client/src/rpc_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub enum RpcRequest {
EthGetTransactionReceipt,
EthCall,
EthEstimateGas,
EthGetLogs,
}

impl fmt::Display for RpcRequest {
Expand Down Expand Up @@ -142,6 +143,7 @@ impl fmt::Display for RpcRequest {
RpcRequest::EthGetTransactionReceipt => "eth_getTransactionReceipt",
RpcRequest::EthCall => "eth_call",
RpcRequest::EthEstimateGas => "eth_estimateGas",
RpcRequest::EthGetLogs => "eth_getLogs",
};

write!(f, "{}", method)
Expand Down
139 changes: 81 additions & 58 deletions core/src/evm_rpc_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use sha3::{Digest, Keccak256};
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
use solana_transaction_status::UiTransactionEncoding;
use std::convert::TryInto;
use std::str::FromStr;

const CHAIN_ID: u64 = 0x77;

Expand All @@ -32,6 +33,16 @@ fn block_to_commitment(block: Option<String>) -> Option<CommitmentConfig> {
Some(CommitmentConfig { commitment })
}

fn block_to_confirmed_num(block: Option<String>, meta: &JsonRpcRequestProcessor) -> Option<u64> {
let block = block?;
match block.as_str() {
"pending" => None,
"earliest" => Some(meta.get_first_available_block()),
"latest" => Some(meta.get_slot(None)),
v => Hex::<u64>::from_hex(&v).ok().map(|f| f.0),
}
}

pub struct ChainMockERPCImpl;
impl ChainMockERPC for ChainMockERPCImpl {
type Metadata = JsonRpcRequestProcessor;
Expand Down Expand Up @@ -116,14 +127,9 @@ impl ChainMockERPC for ChainMockERPCImpl {
&self,
meta: Self::Metadata,
block: String,
_full: bool,
full: bool,
) -> Result<Option<RPCBlock>, Error> {
let num = match block.as_str() {
"pending" => None,
"earliest" => Some(meta.get_first_available_block()),
"latest" => Some(meta.get_slot(None)),
v => Hex::<u64>::from_hex(&v).ok().map(|f| f.0),
};
let num = block_to_confirmed_num(Some(block), &meta);
// TODO: Inline evm_state lookups, and request only solana headers.
let block_num = num.unwrap_or(0);
if block_num == 0 {
Expand All @@ -133,34 +139,31 @@ impl ChainMockERPC for ChainMockERPCImpl {
.get_confirmed_block(block_num, UiTransactionEncoding::Binary.into())
.map_err(|_| Error::NotFound)?
.map(|block| {
use std::str::FromStr;
let block_hash = solana_sdk::hash::Hash::from_str(&block.blockhash).unwrap();
let block_hash = H256::from_slice(&block_hash.0);
let parent_hash =
solana_sdk::hash::Hash::from_str(&block.previous_blockhash).unwrap();
let bank = meta.bank(None);
let evm_lock = bank.evm_state.read().expect("Evm lock poisoned");
let tx_hashes = evm_lock.get_txs_in_block(block_num);
let transactions = tx_hashes
.iter()
.flatten()
.map(|tx_hash| {
(
*tx_hash,
evm_lock
.get_tx_receipt_by_hash(*tx_hash)
.expect("Transaction exist"),
)
})
.filter_map(|(tx_hash, tx)| {
let mut rpc_tx: RPCTransaction = tx.transaction.try_into().ok()?;
rpc_tx.hash = Some(tx_hash.into());
rpc_tx.block_hash = Some(Hex(block_hash.into()));
rpc_tx.block_number = Some(Hex(tx.block_number.into()));
rpc_tx.transaction_index = Some(Hex(tx.index as usize));
Some(rpc_tx)
})
.collect();
let transactions = if full {
let txs = tx_hashes
.iter()
.flatten()
.map(|tx_hash| {
evm_lock
.get_tx_receipt_by_hash(*tx_hash)
.expect("Transaction exist")
})
.filter_map(|receipt| {
RPCTransaction::new_from_receipt(receipt, block_hash.clone()).ok()
})
.collect();
Either::Right(txs)
} else {
let txs = tx_hashes.into_iter().flatten().map(Hex).collect();
Either::Left(txs)
};
drop(evm_lock);

RPCBlock {
Expand All @@ -171,7 +174,7 @@ impl ChainMockERPC for ChainMockERPCImpl {
gas_limit: Hex(0x10000.into()),
gas_used: Gas::zero().into(),
timestamp: Hex(block.block_time.unwrap_or(0) as u64),
transactions: Either::Right(transactions),
transactions,

nonce: 0x7bb9369dcbaec019.into(),
sha3_uncles: H256::zero().into(),
Expand Down Expand Up @@ -324,12 +327,15 @@ impl BasicERPC for BasicERPCImpl {
let receipt = evm_state.get_tx_receipt_by_hash(tx_hash.0);

Ok(match receipt {
Some(tx) => {
let mut rpc_tx: RPCTransaction = tx.transaction.clone().try_into()?;
rpc_tx.hash = Some(tx_hash);
rpc_tx.block_number = Some(Hex(tx.block_number.into()));
rpc_tx.transaction_index = Some(Hex(tx.index as usize));
Some(rpc_tx)
Some(receipt) => {
let block_hash = meta
.get_confirmed_block_hash(receipt.block_number)
.map_err(|_| Error::InvalidParams)?;
let block_hash = block_hash.ok_or(Error::InvalidParams)?;
let block_hash = solana_sdk::hash::Hash::from_str(&block_hash).unwrap();
let block_hash = H256::from_slice(&block_hash.0);

Some(RPCTransaction::new_from_receipt(receipt, block_hash)?)
}
None => None,
})
Expand All @@ -344,25 +350,15 @@ impl BasicERPC for BasicERPCImpl {
let evm_state = bank.evm_state.read().unwrap();
let receipt = evm_state.get_tx_receipt_by_hash(tx_hash.0);
Ok(match receipt {
Some(tx) => Some(RPCReceipt {
transaction_index: Hex(tx.index as usize),
block_hash: H256::zero().into(),
block_number: Hex(tx.block_number.into()),
cumulative_gas_used: tx.used_gas.into(),
gas_used: tx.used_gas.into(),
transaction_hash: tx_hash,
logs: vec![],
contract_address: Some(Hex(tx
.transaction
.address()
.map_err(|_| Error::InvalidParams)?)),
root: H256::zero().into(),
status: Hex(if let evm_state::ExitReason::Succeed(_) = tx.status {
1
} else {
0
}),
}),
Some(receipt) => {
let block_hash = meta
.get_confirmed_block_hash(receipt.block_number)
.map_err(|_| Error::InvalidParams)?;
let block_hash = block_hash.ok_or(Error::InvalidParams)?;
let block_hash = solana_sdk::hash::Hash::from_str(&block_hash).unwrap();
let block_hash = H256::from_slice(&block_hash.0);
Some(RPCReceipt::new_from_receipt(receipt, block_hash)?)
}
None => None,
})
}
Expand All @@ -386,6 +382,28 @@ impl BasicERPC for BasicERPCImpl {
let result = call(meta, tx, block)?;
Ok(Hex(result.2.into()))
}

fn logs(&self, meta: Self::Metadata, log_filter: RPCLogFilter) -> Result<Vec<RPCLog>, Error> {
let bank = meta.bank(None);
let slot = bank.slot();

let evm_lock = bank.evm_state.read().expect("Evm lock poisoned");
let to = block_to_confirmed_num(log_filter.to_block, &meta).unwrap_or(slot);
let from = block_to_confirmed_num(log_filter.from_block, &meta).unwrap_or(slot);

let filter = LogFilter {
address: log_filter.address.map(|k| k.0),
topics: vec![],
from_block: from,
to_block: to,
};

Ok(evm_lock
.get_logs(filter)
.into_iter()
.map(|l| l.into())
.collect())
}
}

fn call(
Expand All @@ -400,7 +418,7 @@ fn call(
let gas_limit: u64 = tx
.gas
.map(|a| a.0)
.unwrap_or_else(|| 300000.into())
.unwrap_or_else(|| 300000000.into())
.try_into()
.map_err(|_| Error::InvalidParams)?;
let gas_limit = gas_limit as usize;
Expand All @@ -415,9 +433,14 @@ fn call(

let mut executor =
evm_state::Executor::with_config(evm_state, Config::istanbul(), gas_limit, bank.slot());
let address = tx.to.map(|h| h.0).unwrap_or_default();
let result =
executor.with_executor(|e| e.transact_call(caller, address, value, input, gas_limit));

let result = if let Some(address) = tx.to {
let address = address.0;
executor.with_executor(|e| e.transact_call(caller, address, value, input, gas_limit))
} else {
executor.with_executor(|e| (e.transact_create(caller, value, input, gas_limit), vec![]))
};

let gas_used = executor.used_gas();
Ok((result.0, result.1, gas_used))
}
25 changes: 25 additions & 0 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,31 @@ impl JsonRpcRequestProcessor {
}
}

pub fn get_confirmed_block_hash(&self, slot: Slot) -> Result<Option<String>> {
if self.config.enable_rpc_transaction_history
&& slot
<= self
.block_commitment_cache
.read()
.unwrap()
.highest_confirmed_root()
{
let result = self.blockstore.get_confirmed_block_hash(slot);
if result.is_err() {
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
return Ok(self
.runtime_handle
.block_on(bigtable_ledger_storage.get_confirmed_block_hash(slot))
.ok());
}
}
self.check_slot_cleaned_up(&result, slot)?;
Ok(result.ok())
} else {
Err(RpcCustomError::BlockNotAvailable { slot }.into())
}
}

pub fn get_confirmed_blocks(
&self,
start_slot: Slot,
Expand Down
11 changes: 7 additions & 4 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ run_solana_validator() {
declare entrypoint=$2
declare port_range=$3
rpc_url=`solana-gossip rpc-url --timeout 180 --entrypoint $entrypoint` # get rpc url
rpc_url=`solana-gossip rpc-url --timeout 30 --entrypoint $entrypoint` # get rpc url
if [ $? -ne 0 ]; then
rpc_url=http://$(echo $entrypoint | cut -d ':' -f 1):8899
fi
solana-keygen new --no-passphrase -so $datadir/identity.json #try to generate identity
solana-keygen new --no-passphrase -so $datadir/vote-account.json #try to generate vote account

Expand All @@ -32,10 +36,8 @@ run_solana_validator() {
--log - \
--enable-rpc-exit \
--enable-rpc-set-log-filter \
--no-genesis-fetch \
--dynamic-port-range $port_range \
--no-snapshot-fetch \
--snapshot-interval-slots 0 # temporary solution while evm is not persistent
--snapshot-interval-slots 100 # temporary solution while evm is not persistent
}

run_solana_bootstrap() {
Expand All @@ -46,14 +48,15 @@ run_solana_bootstrap() {
solana-validator \
--enable-rpc-exit \
--enable-rpc-set-log-filter \
--enable_rpc_transaction_history \
--gossip-host $host \
--ledger $datadir \
--dynamic-port-range $port_range \
--rpc-port $rpc_port \
--identity $datadir/identity.json \
--vote-account $datadir/vote-account.json \
--log - \
--snapshot-interval-slots 0 # temporary solution while evm is not persistent
--snapshot-interval-slots 100 # temporary solution while evm is not persistent
}

run_evm_bridge() {
Expand Down
8 changes: 4 additions & 4 deletions evm-utils/evm-bridge/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,6 @@ impl BridgeERPC for BridgeERPCImpl {
fn compilers(&self, _meta: Self::Metadata) -> EvmResult<Vec<String>> {
Err(evm_rpc::Error::NotFound)
}

fn logs(&self, _meta: Self::Metadata, _log_filter: RPCLogFilter) -> EvmResult<Vec<RPCLog>> {
Err(evm_rpc::Error::NotFound)
}
}

pub struct ChainMockERPCProxy;
Expand Down Expand Up @@ -453,6 +449,10 @@ impl BasicERPC for BasicERPCProxy {
) -> EvmResult<Hex<Gas>> {
proxy_evm_rpc!(meta.rpc_client, EthEstimateGas, tx, block)
}

fn logs(&self, meta: Self::Metadata, log_filter: RPCLogFilter) -> EvmResult<Vec<RPCLog>> {
proxy_evm_rpc!(meta.rpc_client, EthGetLogs, log_filter)
}
}

macro_rules! proxy_sol_rpc {
Expand Down
Loading

0 comments on commit a91b4f1

Please sign in to comment.