Backporting to beta (#4118)
* Ignore get_price_info test by default. (#4112) * Auto-detect hex encoded bytes in sha3 (#4108) * Auto-detect hex encoded bytes in sha3 * Using types/isHex * Removing unused imports * Use binary chop to estimate gas accurately (#4100) * Initial sketch. * Building. * Fix a few things. * Fix issue, add tracing. * Address grumbles * Raise upper limit if needed * Fix test. * Fixing decoding API with signatures in names (#4125) * Fix call/estimate_gas (#4121) * Return 0 instead of error with out of gas on estimate_gas * Fix stuff up.
This commit is contained in:
		
							parent
							
								
									2b588d57f0
								
							
						
					
					
						commit
						5e70507c78
					
				@ -873,6 +873,81 @@ impl BlockChainClient for Client {
 | 
				
			|||||||
		Ok(ret)
 | 
							Ok(ret)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> {
 | 
				
			||||||
 | 
							let header = self.block_header(block).ok_or(CallError::StatePruned)?;
 | 
				
			||||||
 | 
							let last_hashes = self.build_last_hashes(header.parent_hash());
 | 
				
			||||||
 | 
							let env_info = EnvInfo {
 | 
				
			||||||
 | 
								number: header.number(),
 | 
				
			||||||
 | 
								author: header.author(),
 | 
				
			||||||
 | 
								timestamp: header.timestamp(),
 | 
				
			||||||
 | 
								difficulty: header.difficulty(),
 | 
				
			||||||
 | 
								last_hashes: last_hashes,
 | 
				
			||||||
 | 
								gas_used: U256::zero(),
 | 
				
			||||||
 | 
								gas_limit: U256::max_value(),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							// that's just a copy of the state.
 | 
				
			||||||
 | 
							let mut original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
 | 
				
			||||||
 | 
							let sender = t.sender().map_err(|e| {
 | 
				
			||||||
 | 
								let message = format!("Transaction malformed: {:?}", e);
 | 
				
			||||||
 | 
								ExecutionError::TransactionMalformed(message)
 | 
				
			||||||
 | 
							})?;
 | 
				
			||||||
 | 
							let balance = original_state.balance(&sender);
 | 
				
			||||||
 | 
							let needed_balance = t.value + t.gas * t.gas_price;
 | 
				
			||||||
 | 
							if balance < needed_balance {
 | 
				
			||||||
 | 
								// give the sender a sufficient balance
 | 
				
			||||||
 | 
								original_state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let options = TransactOptions { tracing: true, vm_tracing: false, check_nonce: false };
 | 
				
			||||||
 | 
							let mut tx = t.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let mut cond = |gas| {
 | 
				
			||||||
 | 
								let mut state = original_state.clone();
 | 
				
			||||||
 | 
								tx.gas = gas;
 | 
				
			||||||
 | 
								Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
 | 
				
			||||||
 | 
									.transact(&tx, options.clone())
 | 
				
			||||||
 | 
									.map(|r| r.trace[0].result.succeeded())
 | 
				
			||||||
 | 
									.unwrap_or(false)
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let mut upper = env_info.gas_limit;
 | 
				
			||||||
 | 
							if !cond(upper) {
 | 
				
			||||||
 | 
								// impossible at block gas limit - try `UPPER_CEILING` instead.
 | 
				
			||||||
 | 
								// TODO: consider raising limit by powers of two.
 | 
				
			||||||
 | 
								const UPPER_CEILING: u64 = 1_000_000_000_000u64;
 | 
				
			||||||
 | 
								upper = UPPER_CEILING.into();
 | 
				
			||||||
 | 
								if !cond(upper) {
 | 
				
			||||||
 | 
									trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
 | 
				
			||||||
 | 
									return Err(CallError::Execution(ExecutionError::Internal))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let lower = t.gas_required(&self.engine.schedule(&env_info)).into();
 | 
				
			||||||
 | 
							if cond(lower) {
 | 
				
			||||||
 | 
								trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
 | 
				
			||||||
 | 
								return Ok(lower)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/// Find transition point between `lower` and `upper` where `cond` changes from `false` to `true`.
 | 
				
			||||||
 | 
							/// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
 | 
				
			||||||
 | 
							/// We assert: `cond(lower) = false`, `cond(upper) = true`
 | 
				
			||||||
 | 
							fn binary_chop<F>(mut lower: U256, mut upper: U256, mut cond: F) -> U256 where F: FnMut(U256) -> bool {
 | 
				
			||||||
 | 
								while upper - lower > 1.into() {
 | 
				
			||||||
 | 
									let mid = (lower + upper) / 2.into();
 | 
				
			||||||
 | 
									trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
 | 
				
			||||||
 | 
									let c = cond(mid);
 | 
				
			||||||
 | 
									match c {
 | 
				
			||||||
 | 
										true => upper = mid,
 | 
				
			||||||
 | 
										false => lower = mid,
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								upper
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// binary chop to non-excepting call with gas somewhere between 21000 and block gas limit
 | 
				
			||||||
 | 
							trace!(target: "estimate_gas", "estimate_gas chopping {} .. {}", lower, upper);
 | 
				
			||||||
 | 
							Ok(binary_chop(lower, upper, cond))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
						fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
				
			||||||
		let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
 | 
							let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
 | 
				
			||||||
		let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
 | 
							let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
 | 
				
			||||||
 | 
				
			|||||||
@ -379,6 +379,10 @@ impl BlockChainClient for TestBlockChainClient {
 | 
				
			|||||||
		self.execution_result.read().clone().unwrap()
 | 
							self.execution_result.read().clone().unwrap()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn estimate_gas(&self, _t: &SignedTransaction, _block: BlockId) -> Result<U256, CallError> {
 | 
				
			||||||
 | 
							Ok(21000.into())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
						fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
				
			||||||
		self.execution_result.read().clone().unwrap()
 | 
							self.execution_result.read().clone().unwrap()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -184,6 +184,9 @@ pub trait BlockChainClient : Sync + Send {
 | 
				
			|||||||
	/// Makes a non-persistent transaction call.
 | 
						/// Makes a non-persistent transaction call.
 | 
				
			||||||
	fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError>;
 | 
						fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Estimates how much gas will be necessary for a call.
 | 
				
			||||||
 | 
						fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Replays a given transaction for inspection.
 | 
						/// Replays a given transaction for inspection.
 | 
				
			||||||
	fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>;
 | 
						fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Transaction execution options.
 | 
					/// Transaction execution options.
 | 
				
			||||||
#[derive(Default)]
 | 
					#[derive(Default, Copy, Clone, PartialEq)]
 | 
				
			||||||
pub struct TransactOptions {
 | 
					pub struct TransactOptions {
 | 
				
			||||||
	/// Enable call tracing.
 | 
						/// Enable call tracing.
 | 
				
			||||||
	pub tracing: bool,
 | 
						pub tracing: bool,
 | 
				
			||||||
 | 
				
			|||||||
@ -673,7 +673,7 @@ impl MinerService for Miner {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
						fn call(&self, client: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
 | 
				
			||||||
		let sealing_work = self.sealing_work.lock();
 | 
							let sealing_work = self.sealing_work.lock();
 | 
				
			||||||
		match sealing_work.queue.peek_last_ref() {
 | 
							match sealing_work.queue.peek_last_ref() {
 | 
				
			||||||
			Some(work) => {
 | 
								Some(work) => {
 | 
				
			||||||
@ -681,7 +681,7 @@ impl MinerService for Miner {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				// TODO: merge this code with client.rs's fn call somwhow.
 | 
									// TODO: merge this code with client.rs's fn call somwhow.
 | 
				
			||||||
				let header = block.header();
 | 
									let header = block.header();
 | 
				
			||||||
				let last_hashes = Arc::new(chain.last_hashes());
 | 
									let last_hashes = Arc::new(client.last_hashes());
 | 
				
			||||||
				let env_info = EnvInfo {
 | 
									let env_info = EnvInfo {
 | 
				
			||||||
					number: header.number(),
 | 
										number: header.number(),
 | 
				
			||||||
					author: *header.author(),
 | 
										author: *header.author(),
 | 
				
			||||||
@ -706,16 +706,14 @@ impl MinerService for Miner {
 | 
				
			|||||||
					state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
 | 
										state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
 | 
									let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
 | 
				
			||||||
				let mut ret = Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options)?;
 | 
									let mut ret = Executive::new(&mut state, &env_info, &*self.engine, client.vm_factory()).transact(t, options)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// TODO gav move this into Executive.
 | 
									// TODO gav move this into Executive.
 | 
				
			||||||
				ret.state_diff = original_state.map(|original| state.diff_from(original));
 | 
									ret.state_diff = original_state.map(|original| state.diff_from(original));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Ok(ret)
 | 
									Ok(ret)
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			None => {
 | 
								None => client.call(t, BlockId::Latest, analytics)
 | 
				
			||||||
				chain.call(t, BlockId::Latest, analytics)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -82,7 +82,7 @@ impl PriceInfo {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test] #[ignore]
 | 
				
			||||||
fn should_get_price_info() {
 | 
					fn should_get_price_info() {
 | 
				
			||||||
	use std::sync::Arc;
 | 
						use std::sync::Arc;
 | 
				
			||||||
	use std::time::Duration;
 | 
						use std::time::Duration;
 | 
				
			||||||
 | 
				
			|||||||
@ -391,6 +391,14 @@ impl Res {
 | 
				
			|||||||
			Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
 | 
								Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Did this call fail?
 | 
				
			||||||
 | 
						pub fn succeeded(&self) -> bool {
 | 
				
			||||||
 | 
							match *self {
 | 
				
			||||||
 | 
								Res::Call(_) | Res::Create(_) => true,
 | 
				
			||||||
 | 
								_ => false,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
@ -561,4 +569,3 @@ impl Decodable for VMTrace {
 | 
				
			|||||||
		Ok(res)
 | 
							Ok(res)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//! Transaction data structure.
 | 
					//! Transaction data structure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::ops::Deref;
 | 
					use std::ops::{Deref, DerefMut};
 | 
				
			||||||
use std::cell::*;
 | 
					use std::cell::*;
 | 
				
			||||||
use rlp::*;
 | 
					use rlp::*;
 | 
				
			||||||
use util::sha3::Hashable;
 | 
					use util::sha3::Hashable;
 | 
				
			||||||
@ -239,6 +239,12 @@ impl Deref for SignedTransaction {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DerefMut for SignedTransaction {
 | 
				
			||||||
 | 
						fn deref_mut(&mut self) -> &mut Self::Target {
 | 
				
			||||||
 | 
							&mut self.unsigned
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Decodable for SignedTransaction {
 | 
					impl Decodable for SignedTransaction {
 | 
				
			||||||
	fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
 | 
						fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
 | 
				
			||||||
		let d = decoder.as_rlp();
 | 
							let d = decoder.as_rlp();
 | 
				
			||||||
 | 
				
			|||||||
@ -23,12 +23,12 @@ import { eventSignature } from '../../util/signature';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default class Event {
 | 
					export default class Event {
 | 
				
			||||||
  constructor (abi) {
 | 
					  constructor (abi) {
 | 
				
			||||||
    this._name = abi.name;
 | 
					 | 
				
			||||||
    this._inputs = EventParam.toEventParams(abi.inputs || []);
 | 
					    this._inputs = EventParam.toEventParams(abi.inputs || []);
 | 
				
			||||||
    this._anonymous = !!abi.anonymous;
 | 
					    this._anonymous = !!abi.anonymous;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { id, signature } = eventSignature(this._name, this.inputParamTypes());
 | 
					    const { id, name, signature } = eventSignature(abi.name, this.inputParamTypes());
 | 
				
			||||||
    this._id = id;
 | 
					    this._id = id;
 | 
				
			||||||
 | 
					    this._name = name;
 | 
				
			||||||
    this._signature = signature;
 | 
					    this._signature = signature;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -22,14 +22,14 @@ import { methodSignature } from '../util/signature';
 | 
				
			|||||||
export default class Func {
 | 
					export default class Func {
 | 
				
			||||||
  constructor (abi) {
 | 
					  constructor (abi) {
 | 
				
			||||||
    this._abi = abi;
 | 
					    this._abi = abi;
 | 
				
			||||||
    this._name = abi.name;
 | 
					 | 
				
			||||||
    this._constant = !!abi.constant;
 | 
					    this._constant = !!abi.constant;
 | 
				
			||||||
    this._payable = abi.payable;
 | 
					    this._payable = abi.payable;
 | 
				
			||||||
    this._inputs = Param.toParams(abi.inputs || []);
 | 
					    this._inputs = Param.toParams(abi.inputs || []);
 | 
				
			||||||
    this._outputs = Param.toParams(abi.outputs || []);
 | 
					    this._outputs = Param.toParams(abi.outputs || []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { id, signature } = methodSignature(this._name, this.inputParamTypes());
 | 
					    const { id, name, signature } = methodSignature(abi.name, this.inputParamTypes());
 | 
				
			||||||
    this._id = id;
 | 
					    this._id = id;
 | 
				
			||||||
 | 
					    this._name = name;
 | 
				
			||||||
    this._signature = signature;
 | 
					    this._signature = signature;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,18 @@ describe('abi/spec/Function', () => {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('constructor', () => {
 | 
					  describe('constructor', () => {
 | 
				
			||||||
 | 
					    it('returns signature correctly if name already contains it', () => {
 | 
				
			||||||
 | 
					      const func = new Func({
 | 
				
			||||||
 | 
					        name: 'test(bool,string)',
 | 
				
			||||||
 | 
					        inputs: inputsArr,
 | 
				
			||||||
 | 
					        outputs: outputsArr
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(func.name).to.equal('test');
 | 
				
			||||||
 | 
					      expect(func.id).to.equal('test(bool,string)');
 | 
				
			||||||
 | 
					      expect(func.signature).to.equal('02356205');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('stores the parameters as received', () => {
 | 
					    it('stores the parameters as received', () => {
 | 
				
			||||||
      expect(func.name).to.equal('test');
 | 
					      expect(func.name).to.equal('test');
 | 
				
			||||||
      expect(func.constant).to.be.false;
 | 
					      expect(func.constant).to.be.false;
 | 
				
			||||||
 | 
				
			|||||||
@ -17,15 +17,31 @@
 | 
				
			|||||||
import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
 | 
					import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
 | 
				
			||||||
import { fromParamType } from '../spec/paramType/format';
 | 
					import { fromParamType } from '../spec/paramType/format';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function eventSignature (name, params) {
 | 
					export function eventSignature (eventName, params) {
 | 
				
			||||||
 | 
					  const { strName, name } = parseName(eventName);
 | 
				
			||||||
  const types = (params || []).map(fromParamType).join(',');
 | 
					  const types = (params || []).map(fromParamType).join(',');
 | 
				
			||||||
  const id = `${name || ''}(${types})`;
 | 
					  const id = `${strName}(${types})`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return { id, signature: keccak_256(id) };
 | 
					  return { id, name, signature: keccak_256(id) };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function methodSignature (name, params) {
 | 
					export function methodSignature (methodName, params) {
 | 
				
			||||||
  const { id, signature } = eventSignature(name, params);
 | 
					  const { id, name, signature } = eventSignature(methodName, params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return { id, signature: signature.substr(0, 8) };
 | 
					  return { id, name, signature: signature.substr(0, 8) };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function parseName (name) {
 | 
				
			||||||
 | 
					  const strName = `${name || ''}`;
 | 
				
			||||||
 | 
					  const idx = strName.indexOf('(');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (idx === -1) {
 | 
				
			||||||
 | 
					    return { strName, name };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const trimmedName = strName.slice(0, idx);
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    strName: trimmedName,
 | 
				
			||||||
 | 
					    name: trimmedName
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,50 +19,93 @@ import { eventSignature, methodSignature } from './signature';
 | 
				
			|||||||
describe('abi/util/signature', () => {
 | 
					describe('abi/util/signature', () => {
 | 
				
			||||||
  describe('eventSignature', () => {
 | 
					  describe('eventSignature', () => {
 | 
				
			||||||
    it('encodes signature baz() correctly', () => {
 | 
					    it('encodes signature baz() correctly', () => {
 | 
				
			||||||
      expect(eventSignature('baz', []))
 | 
					      expect(eventSignature('baz', [])).to.deep.equal({
 | 
				
			||||||
        .to.deep.equal({ id: 'baz()', signature: 'a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf' });
 | 
					        id: 'baz()',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: 'a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes signature baz(uint32) correctly', () => {
 | 
					    it('encodes signature baz(uint32) correctly', () => {
 | 
				
			||||||
      expect(eventSignature('baz', [{ type: 'uint', length: 32 }]))
 | 
					      expect(eventSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
 | 
				
			||||||
        .to.deep.equal({ id: 'baz(uint32)', signature: '7d68785e8fc871be024b75964bd86d093511d4bc2dc7cf7bea32c48a0efaecb1' });
 | 
					        id: 'baz(uint32)',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: '7d68785e8fc871be024b75964bd86d093511d4bc2dc7cf7bea32c48a0efaecb1'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes signature baz(uint32, bool) correctly', () => {
 | 
					    it('encodes signature baz(uint32, bool) correctly', () => {
 | 
				
			||||||
      expect(eventSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }]))
 | 
					      expect(eventSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
 | 
				
			||||||
        .to.deep.equal({ id: 'baz(uint32,bool)', signature: 'cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2' });
 | 
					        id: 'baz(uint32,bool)',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: 'cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes no-name signature correctly as ()', () => {
 | 
					    it('encodes no-name signature correctly as ()', () => {
 | 
				
			||||||
      expect(eventSignature(undefined, []))
 | 
					      expect(eventSignature(undefined, [])).to.deep.equal({
 | 
				
			||||||
        .to.deep.equal({ id: '()', signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe' });
 | 
					        id: '()',
 | 
				
			||||||
 | 
					        name: undefined,
 | 
				
			||||||
 | 
					        signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes no-params signature correctly as ()', () => {
 | 
					    it('encodes no-params signature correctly as ()', () => {
 | 
				
			||||||
      expect(eventSignature(undefined, undefined))
 | 
					      expect(eventSignature(undefined, undefined)).to.deep.equal({
 | 
				
			||||||
        .to.deep.equal({ id: '()', signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe' });
 | 
					        id: '()',
 | 
				
			||||||
 | 
					        name: undefined,
 | 
				
			||||||
 | 
					        signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('methodSignature', () => {
 | 
					  describe('methodSignature', () => {
 | 
				
			||||||
    it('encodes signature baz() correctly', () => {
 | 
					    it('encodes signature baz() correctly', () => {
 | 
				
			||||||
      expect(methodSignature('baz', [])).to.deep.equal({ id: 'baz()', signature: 'a7916fac' });
 | 
					      expect(methodSignature('baz', [])).to.deep.equal({
 | 
				
			||||||
 | 
					        id: 'baz()',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: 'a7916fac'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes signature baz(uint32) correctly', () => {
 | 
					    it('encodes signature baz(uint32) correctly', () => {
 | 
				
			||||||
      expect(methodSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({ id: 'baz(uint32)', signature: '7d68785e' });
 | 
					      expect(methodSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
 | 
				
			||||||
 | 
					        id: 'baz(uint32)',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: '7d68785e'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes signature baz(uint32, bool) correctly', () => {
 | 
					    it('encodes signature baz(uint32, bool) correctly', () => {
 | 
				
			||||||
      expect(methodSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({ id: 'baz(uint32,bool)', signature: 'cdcd77c0' });
 | 
					      expect(methodSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
 | 
				
			||||||
 | 
					        id: 'baz(uint32,bool)',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: 'cdcd77c0'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('encodes signature in name correctly', () => {
 | 
				
			||||||
 | 
					      expect(methodSignature('baz(uint32,bool)', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
 | 
				
			||||||
 | 
					        id: 'baz(uint32,bool)',
 | 
				
			||||||
 | 
					        name: 'baz',
 | 
				
			||||||
 | 
					        signature: 'cdcd77c0'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes no-name signature correctly as ()', () => {
 | 
					    it('encodes no-name signature correctly as ()', () => {
 | 
				
			||||||
      expect(methodSignature(undefined, [])).to.deep.equal({ id: '()', signature: '861731d5' });
 | 
					      expect(methodSignature(undefined, [])).to.deep.equal({
 | 
				
			||||||
 | 
					        id: '()',
 | 
				
			||||||
 | 
					        name: undefined,
 | 
				
			||||||
 | 
					        signature: '861731d5'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('encodes no-params signature correctly as ()', () => {
 | 
					    it('encodes no-params signature correctly as ()', () => {
 | 
				
			||||||
      expect(methodSignature(undefined, undefined)).to.deep.equal({ id: '()', signature: '861731d5' });
 | 
					      expect(methodSignature(undefined, undefined)).to.deep.equal({
 | 
				
			||||||
 | 
					        id: '()',
 | 
				
			||||||
 | 
					        name: undefined,
 | 
				
			||||||
 | 
					        signature: '861731d5'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -17,9 +17,12 @@
 | 
				
			|||||||
import { keccak_256 } from 'js-sha3'; // eslint-disable-line
 | 
					import { keccak_256 } from 'js-sha3'; // eslint-disable-line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { hexToBytes } from './format';
 | 
					import { hexToBytes } from './format';
 | 
				
			||||||
 | 
					import { isHex } from './types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function sha3 (value, options) {
 | 
					export function sha3 (value, options) {
 | 
				
			||||||
  if (options && options.encoding === 'hex') {
 | 
					  const forceHex = options && options.encoding === 'hex';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (forceHex || (!options && isHex(value))) {
 | 
				
			||||||
    const bytes = hexToBytes(value);
 | 
					    const bytes = hexToBytes(value);
 | 
				
			||||||
    return sha3(bytes);
 | 
					    return sha3(bytes);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -28,3 +31,5 @@ export function sha3 (value, options) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return `0x${hash}`;
 | 
					  return `0x${hash}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sha3.text = (val) => sha3(val, { encoding: 'raw' });
 | 
				
			||||||
 | 
				
			|||||||
@ -32,5 +32,14 @@ describe('api/util/sha3', () => {
 | 
				
			|||||||
      expect(sha3('01020304', { encoding: 'hex' })).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
 | 
					      expect(sha3('01020304', { encoding: 'hex' })).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
 | 
				
			||||||
      expect(sha3(Uint8Array.from([1, 2, 3, 4]))).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
 | 
					      expect(sha3(Uint8Array.from([1, 2, 3, 4]))).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should interpret as bytes by default', () => {
 | 
				
			||||||
 | 
					      expect(sha3('0x01020304')).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should force text if option is passed', () => {
 | 
				
			||||||
 | 
					      expect(sha3('0x01020304', { encoding: 'raw' })).to.equal('0x16bff43de576d28857dcba65a56fc17c5e93c09bd6a709268eff8e62025ae869');
 | 
				
			||||||
 | 
					      expect(sha3.text('0x01020304')).to.equal('0x16bff43de576d28857dcba65a56fc17c5e93c09bd6a709268eff8e62025ae869');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,10 @@ export function isFunction (test) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function isHex (_test) {
 | 
					export function isHex (_test) {
 | 
				
			||||||
 | 
					  if (!isString(_test)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (_test.substr(0, 2) === '0x') {
 | 
					  if (_test.substr(0, 2) === '0x') {
 | 
				
			||||||
    return isHex(_test.slice(2));
 | 
					    return isHex(_test.slice(2));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -66,6 +66,12 @@ describe('api/util/types', () => {
 | 
				
			|||||||
    it('correctly identifies non-hex values', () => {
 | 
					    it('correctly identifies non-hex values', () => {
 | 
				
			||||||
      expect(isHex('123j')).to.be.false;
 | 
					      expect(isHex('123j')).to.be.false;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('correctly indentifies non-string values', () => {
 | 
				
			||||||
 | 
					      expect(isHex(false)).to.be.false;
 | 
				
			||||||
 | 
					      expect(isHex()).to.be.false;
 | 
				
			||||||
 | 
					      expect(isHex([1, 2, 3])).to.be.false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('isInstanceOf', () => {
 | 
					  describe('isInstanceOf', () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -91,7 +91,7 @@ export default class Registry {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  lookupAddress (_name) {
 | 
					  lookupAddress (_name) {
 | 
				
			||||||
    const name = _name.toLowerCase();
 | 
					    const name = _name.toLowerCase();
 | 
				
			||||||
    const sha3 = this._api.util.sha3(name);
 | 
					    const sha3 = this._api.util.sha3.text(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this.getInstance().then((instance) => {
 | 
					    return this.getInstance().then((instance) => {
 | 
				
			||||||
      return instance.getAddress.call({}, [sha3, 'A']);
 | 
					      return instance.getAddress.call({}, [sha3, 'A']);
 | 
				
			||||||
 | 
				
			|||||||
@ -39,7 +39,7 @@ export const lookup = (name, key) => (dispatch, getState) => {
 | 
				
			|||||||
  name = name.toLowerCase();
 | 
					  name = name.toLowerCase();
 | 
				
			||||||
  dispatch(lookupStart(name, key));
 | 
					  dispatch(lookupStart(name, key));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getAddress.call({}, [ sha3(name), key ])
 | 
					  getAddress.call({}, [ sha3.text(name), key ])
 | 
				
			||||||
    .then((address) => dispatch(success('lookup', address)))
 | 
					    .then((address) => dispatch(success('lookup', address)))
 | 
				
			||||||
    .catch((err) => {
 | 
					    .catch((err) => {
 | 
				
			||||||
      console.error(`could not lookup ${key} for ${name}`);
 | 
					      console.error(`could not lookup ${key} for ${name}`);
 | 
				
			||||||
 | 
				
			|||||||
@ -62,7 +62,7 @@ export const reserve = (name) => (dispatch, getState) => {
 | 
				
			|||||||
        value: fee
 | 
					        value: fee
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      const values = [
 | 
					      const values = [
 | 
				
			||||||
        sha3(name)
 | 
					        sha3.text(name)
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return postTx(api, reserve, options, values);
 | 
					      return postTx(api, reserve, options, values);
 | 
				
			||||||
@ -116,7 +116,7 @@ export const drop = (name) => (dispatch, getState) => {
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const values = [
 | 
					      const values = [
 | 
				
			||||||
        sha3(name)
 | 
					        sha3.text(name)
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return postTx(api, drop, options, values);
 | 
					      return postTx(api, drop, options, values);
 | 
				
			||||||
 | 
				
			|||||||
@ -54,7 +54,7 @@ export const update = (name, key, value) => (dispatch, getState) => {
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const values = [
 | 
					      const values = [
 | 
				
			||||||
        sha3(name),
 | 
					        sha3.text(name),
 | 
				
			||||||
        key,
 | 
					        key,
 | 
				
			||||||
        value
 | 
					        value
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
export const getOwner = (contract, name) => {
 | 
					export const getOwner = (contract, name) => {
 | 
				
			||||||
  const { address, api } = contract;
 | 
					  const { address, api } = contract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const key = api.util.sha3(name) + '0000000000000000000000000000000000000000000000000000000000000001';
 | 
					  const key = api.util.sha3.text(name) + '0000000000000000000000000000000000000000000000000000000000000001';
 | 
				
			||||||
  const position = api.util.sha3(key, { encoding: 'hex' });
 | 
					  const position = api.util.sha3(key, { encoding: 'hex' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return api
 | 
					  return api
 | 
				
			||||||
 | 
				
			|||||||
@ -68,13 +68,13 @@ const STORE = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function createApi (result = true) {
 | 
					function createApi (result = true) {
 | 
				
			||||||
 | 
					  const sha3 = sinon.stub().resolves('0x0000000000000000000000000000000000000000');
 | 
				
			||||||
 | 
					  sha3.text = sha3;
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    parity: {
 | 
					    parity: {
 | 
				
			||||||
      registryAddress: sinon.stub().resolves('0x0000000000000000000000000000000000000000')
 | 
					      registryAddress: sinon.stub().resolves('0x0000000000000000000000000000000000000000')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    util: {
 | 
					    util: { sha3 }
 | 
				
			||||||
      sha3: sinon.stub().resolves('0x0000000000000000000000000000000000000000')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,7 @@ export default class EmailVerificationStore extends VerificationStore {
 | 
				
			|||||||
    super(api, EmailVerificationABI, EMAIL_VERIFICATION, account, isTestnet);
 | 
					    super(api, EmailVerificationABI, EMAIL_VERIFICATION, account, isTestnet);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  requestValues = () => [ sha3(this.email) ]
 | 
					  requestValues = () => [ sha3.text(this.email) ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @action setEmail = (email) => {
 | 
					  @action setEmail = (email) => {
 | 
				
			||||||
    this.email = email;
 | 
					    this.email = email;
 | 
				
			||||||
 | 
				
			|||||||
@ -120,7 +120,7 @@ export default class VerificationStore {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const confirm = contract.functions.find((fn) => fn.name === 'confirm');
 | 
					    const confirm = contract.functions.find((fn) => fn.name === 'confirm');
 | 
				
			||||||
    const options = { from: account };
 | 
					    const options = { from: account };
 | 
				
			||||||
    const values = [ sha3(code) ];
 | 
					    const values = [ sha3.text(code) ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.code = code;
 | 
					    this.code = code;
 | 
				
			||||||
    this.isCodeValid = null;
 | 
					    this.isCodeValid = null;
 | 
				
			||||||
@ -192,7 +192,7 @@ export default class VerificationStore {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @action sendConfirmation = () => {
 | 
					  @action sendConfirmation = () => {
 | 
				
			||||||
    const { api, account, contract, code } = this;
 | 
					    const { api, account, contract, code } = this;
 | 
				
			||||||
    const token = sha3(code);
 | 
					    const token = sha3.text(code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const confirm = contract.functions.find((fn) => fn.name === 'confirm');
 | 
					    const confirm = contract.functions.find((fn) => fn.name === 'confirm');
 | 
				
			||||||
    const options = { from: account };
 | 
					    const options = { from: account };
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,7 @@ export default class AddressSelectStore {
 | 
				
			|||||||
          return emailVerification
 | 
					          return emailVerification
 | 
				
			||||||
            .instance
 | 
					            .instance
 | 
				
			||||||
            .reverse
 | 
					            .reverse
 | 
				
			||||||
            .call({}, [ sha3(email) ])
 | 
					            .call({}, [ sha3.text(email) ])
 | 
				
			||||||
            .then((address) => {
 | 
					            .then((address) => {
 | 
				
			||||||
              return {
 | 
					              return {
 | 
				
			||||||
                address,
 | 
					                address,
 | 
				
			||||||
@ -109,7 +109,7 @@ export default class AddressSelectStore {
 | 
				
			|||||||
        this.regLookups.push((name) => {
 | 
					        this.regLookups.push((name) => {
 | 
				
			||||||
          return registryInstance
 | 
					          return registryInstance
 | 
				
			||||||
            .getAddress
 | 
					            .getAddress
 | 
				
			||||||
            .call({}, [ sha3(name), 'A' ])
 | 
					            .call({}, [ sha3.text(name), 'A' ])
 | 
				
			||||||
            .then((address) => {
 | 
					            .then((address) => {
 | 
				
			||||||
              return {
 | 
					              return {
 | 
				
			||||||
                address,
 | 
					                address,
 | 
				
			||||||
 | 
				
			|||||||
@ -141,7 +141,7 @@ class Background extends Component {
 | 
				
			|||||||
  generateSeed () {
 | 
					  generateSeed () {
 | 
				
			||||||
    const { api, muiTheme } = this.context;
 | 
					    const { api, muiTheme } = this.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return api.util.sha3(`${muiTheme.backgroundSeed}${Math.random()}${counter++}`);
 | 
					    return api.util.sha3.text(`${muiTheme.backgroundSeed}${Math.random()}${counter++}`);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -671,13 +671,8 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		let request = CallRequest::into(request);
 | 
							let request = CallRequest::into(request);
 | 
				
			||||||
		let signed = self.sign_call(request)?;
 | 
							let signed = self.sign_call(request)?;
 | 
				
			||||||
		let result = match num.0 {
 | 
							take_weak!(self.client).estimate_gas(&signed, num.0.into())
 | 
				
			||||||
			BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
 | 
								.map(Into::into)
 | 
				
			||||||
			num => take_weak!(self.client).call(&signed, num.into(), Default::default()),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		result
 | 
					 | 
				
			||||||
			.map(|res| (res.gas_used + res.refunded).into())
 | 
					 | 
				
			||||||
			.map_err(errors::from_call_error)
 | 
								.map_err(errors::from_call_error)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -691,7 +691,7 @@ fn rpc_eth_estimate_gas() {
 | 
				
			|||||||
		"latest"],
 | 
							"latest"],
 | 
				
			||||||
		"id": 1
 | 
							"id": 1
 | 
				
			||||||
	}"#;
 | 
						}"#;
 | 
				
			||||||
	let response = r#"{"jsonrpc":"2.0","result":"0xff35","id":1}"#;
 | 
						let response = r#"{"jsonrpc":"2.0","result":"0x5208","id":1}"#;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
 | 
						assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -725,7 +725,7 @@ fn rpc_eth_estimate_gas_default_block() {
 | 
				
			|||||||
		}],
 | 
							}],
 | 
				
			||||||
		"id": 1
 | 
							"id": 1
 | 
				
			||||||
	}"#;
 | 
						}"#;
 | 
				
			||||||
	let response = r#"{"jsonrpc":"2.0","result":"0xff35","id":1}"#;
 | 
						let response = r#"{"jsonrpc":"2.0","result":"0x5208","id":1}"#;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
 | 
						assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user