Merge branch 'master' into close_gently
Conflicts: parity/main.rs
This commit is contained in:
commit
6b0cc0c8fa
10
.travis.yml
10
.travis.yml
@ -37,11 +37,11 @@ after_success: |
|
|||||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||||
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
|
||||||
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
cargo test --no-run ${KCOV_FEATURES} ${TARGETS} &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore_util-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethash-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethsync-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore_rpc-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* &&
|
||||||
./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* &&
|
./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* &&
|
||||||
[ $TRAVIS_BRANCH = master ] &&
|
[ $TRAVIS_BRANCH = master ] &&
|
||||||
[ $TRAVIS_PULL_REQUEST = false ] &&
|
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||||
|
@ -18,6 +18,7 @@ ethcore = { path = "ethcore" }
|
|||||||
ethsync = { path = "sync" }
|
ethsync = { path = "sync" }
|
||||||
ethcore-rpc = { path = "rpc", optional = true }
|
ethcore-rpc = { path = "rpc", optional = true }
|
||||||
fdlimit = { path = "util/fdlimit" }
|
fdlimit = { path = "util/fdlimit" }
|
||||||
|
target_info = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rpc"]
|
default = ["rpc"]
|
||||||
|
10
cov.sh
10
cov.sh
@ -18,9 +18,9 @@ fi
|
|||||||
cargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $?
|
cargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $?
|
||||||
rm -rf target/coverage
|
rm -rf target/coverage
|
||||||
mkdir -p target/coverage
|
mkdir -p target/coverage
|
||||||
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-*
|
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-*
|
||||||
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-*
|
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-*
|
||||||
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-*
|
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-*
|
||||||
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-*
|
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-*
|
||||||
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-*
|
kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-*
|
||||||
xdg-open target/coverage/index.html
|
xdg-open target/coverage/index.html
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||||
"enode://859bbe6926fc161d218f62bd2efe0b4f6980205c00a5b928ccee39c94c440b73a054ece5db36beddd71963fbd296af61ec72a591f72a2299f9a046bd6d6ce1a9@parity-node-zero.ethcore.io:30303"
|
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303"
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
|
||||||
|
@ -183,11 +183,11 @@ impl Account {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
||||||
pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
|
pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
||||||
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
|
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
|
||||||
|
|
||||||
/// return the storage overlay.
|
/// return the storage overlay.
|
||||||
pub fn storage_overlay(&self) -> Ref<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
|
pub fn storage_overlay(&self) -> Ref<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
|
||||||
|
|
||||||
@ -198,7 +198,11 @@ impl Account {
|
|||||||
pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
|
pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
|
||||||
|
|
||||||
/// Increment the nonce of the account by one.
|
/// Increment the nonce of the account by one.
|
||||||
pub fn sub_balance(&mut self, x: &U256) { self.balance = self.balance - *x; }
|
/// Panics if balance is less than `x`
|
||||||
|
pub fn sub_balance(&mut self, x: &U256) {
|
||||||
|
assert!(self.balance >= *x);
|
||||||
|
self.balance = self.balance - *x;
|
||||||
|
}
|
||||||
|
|
||||||
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
||||||
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
|
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
|
||||||
|
@ -85,6 +85,9 @@ pub trait BlockProvider {
|
|||||||
/// Get the hash of given block's number.
|
/// Get the hash of given block's number.
|
||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256>;
|
fn block_hash(&self, index: BlockNumber) -> Option<H256>;
|
||||||
|
|
||||||
|
/// Get the address of transaction with given hash.
|
||||||
|
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress>;
|
||||||
|
|
||||||
/// Get the partial-header of a block.
|
/// Get the partial-header of a block.
|
||||||
fn block_header(&self, hash: &H256) -> Option<Header> {
|
fn block_header(&self, hash: &H256) -> Option<Header> {
|
||||||
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
|
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
|
||||||
@ -107,6 +110,16 @@ pub trait BlockProvider {
|
|||||||
self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
|
self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get transaction with given transaction hash.
|
||||||
|
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
||||||
|
self.transaction_address(hash).and_then(|address| self.transaction_at(&address))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get transaction at given address.
|
||||||
|
fn transaction_at(&self, address: &TransactionAddress) -> Option<SignedTransaction> {
|
||||||
|
self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).transactions()).and_then(|t| t.into_iter().nth(address.index))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a list of transactions for a given block.
|
/// Get a list of transactions for a given block.
|
||||||
/// Returns None if block deos not exist.
|
/// Returns None if block deos not exist.
|
||||||
fn transactions(&self, hash: &H256) -> Option<Vec<SignedTransaction>> {
|
fn transactions(&self, hash: &H256) -> Option<Vec<SignedTransaction>> {
|
||||||
@ -201,6 +214,11 @@ impl BlockProvider for BlockChain {
|
|||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
||||||
self.query_extras(&index, &self.block_hashes)
|
self.query_extras(&index, &self.block_hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the address of transaction with given hash.
|
||||||
|
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
|
||||||
|
self.query_extras(hash, &self.transaction_addresses)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const COLLECTION_QUEUE_SIZE: usize = 8;
|
const COLLECTION_QUEUE_SIZE: usize = 8;
|
||||||
@ -474,6 +492,14 @@ impl BlockChain {
|
|||||||
parent_details.children.push(hash.clone());
|
parent_details.children.push(hash.clone());
|
||||||
batch.put_extras(&parent_hash, &parent_details);
|
batch.put_extras(&parent_hash, &parent_details);
|
||||||
|
|
||||||
|
// update transaction addresses
|
||||||
|
for (i, tx_hash) in block.transaction_hashes().iter().enumerate() {
|
||||||
|
batch.put_extras(tx_hash, &TransactionAddress {
|
||||||
|
block_hash: hash.clone(),
|
||||||
|
index: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// if it's not new best block, just return
|
// if it's not new best block, just return
|
||||||
if !is_new_best {
|
if !is_new_best {
|
||||||
return (batch, None, details);
|
return (batch, None, details);
|
||||||
@ -824,4 +850,21 @@ mod tests {
|
|||||||
let bc = bc_result.reference();
|
let bc = bc_result.reference();
|
||||||
assert_eq!(bc.best_block_number(), 0);
|
assert_eq!(bc.best_block_number(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find_transaction_by_hash() {
|
||||||
|
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
|
||||||
|
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
|
||||||
|
let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap();
|
||||||
|
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
let bc = BlockChain::new(&genesis, temp.as_path());
|
||||||
|
bc.insert_block(&b1);
|
||||||
|
|
||||||
|
let transactions = bc.transactions(&b1_hash).unwrap();
|
||||||
|
assert_eq!(transactions.len(), 7);
|
||||||
|
for t in transactions {
|
||||||
|
assert_eq!(bc.transaction(&t.hash()).unwrap(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Get block total difficulty.
|
/// Get block total difficulty.
|
||||||
fn block_total_difficulty(&self, hash: &H256) -> Option<U256>;
|
fn block_total_difficulty(&self, hash: &H256) -> Option<U256>;
|
||||||
|
|
||||||
|
/// Get address code.
|
||||||
|
fn code(&self, address: &Address) -> Option<Bytes>;
|
||||||
|
|
||||||
/// Get raw block header data by block number.
|
/// Get raw block header data by block number.
|
||||||
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
||||||
|
|
||||||
@ -163,7 +166,7 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY: u64 = 1000;
|
const HISTORY: u64 = 1000;
|
||||||
const CLIENT_DB_VER_STR: &'static str = "1.0";
|
const CLIENT_DB_VER_STR: &'static str = "2.0";
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Create a new client with given spec and DB path.
|
/// Create a new client with given spec and DB path.
|
||||||
@ -367,6 +370,10 @@ impl BlockChainClient for Client {
|
|||||||
self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty)
|
self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn code(&self, address: &Address) -> Option<Bytes> {
|
||||||
|
self.state().code(address)
|
||||||
|
}
|
||||||
|
|
||||||
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
|
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
|
||||||
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
|
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,6 @@ use spec::*;
|
|||||||
use engine::*;
|
use engine::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use evm::Factory;
|
use evm::Factory;
|
||||||
#[cfg(test)]
|
|
||||||
use tests::helpers::*;
|
|
||||||
|
|
||||||
/// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum
|
/// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum
|
||||||
/// mainnet chains in the Olympic, Frontier and Homestead eras.
|
/// mainnet chains in the Olympic, Frontier and Homestead eras.
|
||||||
@ -49,6 +47,17 @@ impl Ethash {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn new_test(spec: Spec) -> Ethash {
|
||||||
|
Ethash {
|
||||||
|
spec: spec,
|
||||||
|
pow: EthashManager::new(),
|
||||||
|
factory: Factory::default(),
|
||||||
|
u64_params: RwLock::new(HashMap::new()),
|
||||||
|
u256_params: RwLock::new(HashMap::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn u64_param(&self, name: &str) -> u64 {
|
fn u64_param(&self, name: &str) -> u64 {
|
||||||
*self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(||
|
*self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(||
|
||||||
self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a)))
|
self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a)))
|
||||||
@ -123,6 +132,11 @@ impl Engine for Ethash {
|
|||||||
|
|
||||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
// check the seal fields.
|
// check the seal fields.
|
||||||
|
if header.seal.len() != self.seal_fields() {
|
||||||
|
return Err(From::from(BlockError::InvalidSealArity(
|
||||||
|
Mismatch { expected: self.seal_fields(), found: header.seal.len() }
|
||||||
|
)));
|
||||||
|
}
|
||||||
try!(UntrustedRlp::new(&header.seal[0]).as_val::<H256>());
|
try!(UntrustedRlp::new(&header.seal[0]).as_val::<H256>());
|
||||||
try!(UntrustedRlp::new(&header.seal[1]).as_val::<H64>());
|
try!(UntrustedRlp::new(&header.seal[1]).as_val::<H64>());
|
||||||
|
|
||||||
@ -143,6 +157,11 @@ impl Engine for Ethash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
|
if header.seal.len() != self.seal_fields() {
|
||||||
|
return Err(From::from(BlockError::InvalidSealArity(
|
||||||
|
Mismatch { expected: self.seal_fields(), found: header.seal.len() }
|
||||||
|
)));
|
||||||
|
}
|
||||||
let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64());
|
let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64());
|
||||||
let mix = Ethash::from_ethash(result.mix_hash);
|
let mix = Ethash::from_ethash(result.mix_hash);
|
||||||
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value));
|
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value));
|
||||||
@ -156,6 +175,11 @@ impl Engine for Ethash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
|
// we should not calculate difficulty for genesis blocks
|
||||||
|
if header.number() == 0 {
|
||||||
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
|
}
|
||||||
|
|
||||||
// Check difficulty is correct given the two timestamps.
|
// Check difficulty is correct given the two timestamps.
|
||||||
let expected_difficulty = self.calculate_difficuty(header, parent);
|
let expected_difficulty = self.calculate_difficuty(header, parent);
|
||||||
if header.difficulty != expected_difficulty {
|
if header.difficulty != expected_difficulty {
|
||||||
@ -242,38 +266,236 @@ impl Header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn on_close_block() {
|
mod tests {
|
||||||
|
extern crate ethash;
|
||||||
|
|
||||||
|
use common::*;
|
||||||
|
use block::*;
|
||||||
|
use engine::*;
|
||||||
|
use tests::helpers::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
let engine = new_morden().to_engine().unwrap();
|
use super::super::new_morden;
|
||||||
let genesis_header = engine.spec().genesis_header();
|
|
||||||
let mut db_result = get_temp_journal_db();
|
#[test]
|
||||||
let mut db = db_result.take();
|
fn on_close_block() {
|
||||||
engine.spec().ensure_db_good(&mut db);
|
let engine = new_morden().to_engine().unwrap();
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let genesis_header = engine.spec().genesis_header();
|
||||||
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
let mut db_result = get_temp_journal_db();
|
||||||
let b = b.close();
|
let mut db = db_result.take();
|
||||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
engine.spec().ensure_db_good(&mut db);
|
||||||
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
|
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
||||||
|
let b = b.close();
|
||||||
|
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn on_close_block_with_uncle() {
|
||||||
|
let engine = new_morden().to_engine().unwrap();
|
||||||
|
let genesis_header = engine.spec().genesis_header();
|
||||||
|
let mut db_result = get_temp_journal_db();
|
||||||
|
let mut db = db_result.take();
|
||||||
|
engine.spec().ensure_db_good(&mut db);
|
||||||
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
|
let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
||||||
|
let mut uncle = Header::new();
|
||||||
|
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
||||||
|
uncle.author = uncle_author.clone();
|
||||||
|
b.push_uncle(uncle).unwrap();
|
||||||
|
|
||||||
|
let b = b.close();
|
||||||
|
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap());
|
||||||
|
assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn has_valid_metadata() {
|
||||||
|
let engine = Ethash::new_boxed(new_morden());
|
||||||
|
assert!(!engine.name().is_empty());
|
||||||
|
assert!(engine.version().major >= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_return_params() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
assert!(engine.u64_param("durationLimit") > 0);
|
||||||
|
assert!(engine.u256_param("minimumDifficulty") > U256::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_return_factory() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
engine.vm_factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_return_schedule() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let schedule = engine.schedule(&EnvInfo {
|
||||||
|
number: 10000000,
|
||||||
|
author: x!(0),
|
||||||
|
timestamp: 0,
|
||||||
|
difficulty: x!(0),
|
||||||
|
last_hashes: vec![],
|
||||||
|
gas_used: x!(0),
|
||||||
|
gas_limit: x!(0)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(schedule.stack_limit > 0);
|
||||||
|
|
||||||
|
let schedule = engine.schedule(&EnvInfo {
|
||||||
|
number: 100,
|
||||||
|
author: x!(0),
|
||||||
|
timestamp: 0,
|
||||||
|
difficulty: x!(0),
|
||||||
|
last_hashes: vec![],
|
||||||
|
gas_used: x!(0),
|
||||||
|
gas_limit: x!(0)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(!schedule.have_delegate_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_seal_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let header: Header = Header::default();
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_basic(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidSealArity(_))) => {},
|
||||||
|
Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_difficulty_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]);
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_basic(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {},
|
||||||
|
Err(_) => { panic!("should be block difficulty error (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_proof_of_work_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]);
|
||||||
|
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_basic(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid proof of work error (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_seal_unordered_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let header: Header = Header::default();
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_unordered(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidSealArity(_))) => {},
|
||||||
|
Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_seal256_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]);
|
||||||
|
let verify_result = engine.verify_block_unordered(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid 256-bit seal fail (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_do_proof_of_work_unordered_verification_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).to_vec(), rlp::encode(&H64::zero()).to_vec()]);
|
||||||
|
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_unordered(&header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_verify_block_family_genesis_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let header: Header = Header::default();
|
||||||
|
let parent_header: Header = Header::default();
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_family(&header, &parent_header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::RidiculousNumber(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid block number fail (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_verify_block_family_difficulty_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_number(2);
|
||||||
|
let mut parent_header: Header = Header::default();
|
||||||
|
parent_header.set_number(1);
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_family(&header, &parent_header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidDifficulty(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_verify_block_family_gas_fail() {
|
||||||
|
let engine = Ethash::new_test(new_morden());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_number(2);
|
||||||
|
header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap());
|
||||||
|
let mut parent_header: Header = Header::default();
|
||||||
|
parent_header.set_number(1);
|
||||||
|
|
||||||
|
let verify_result = engine.verify_block_family(&header, &parent_header, None);
|
||||||
|
|
||||||
|
match verify_result {
|
||||||
|
Err(Error::Block(BlockError::InvalidGasLimit(_))) => {},
|
||||||
|
Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); },
|
||||||
|
_ => { panic!("Should be error, got Ok"); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: difficulty test
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn on_close_block_with_uncle() {
|
|
||||||
use super::*;
|
|
||||||
let engine = new_morden().to_engine().unwrap();
|
|
||||||
let genesis_header = engine.spec().genesis_header();
|
|
||||||
let mut db_result = get_temp_journal_db();
|
|
||||||
let mut db = db_result.take();
|
|
||||||
engine.spec().ensure_db_good(&mut db);
|
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
|
||||||
let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
|
||||||
let mut uncle = Header::new();
|
|
||||||
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
|
||||||
uncle.author = uncle_author.clone();
|
|
||||||
b.push_uncle(uncle).unwrap();
|
|
||||||
|
|
||||||
let b = b.close();
|
|
||||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap());
|
|
||||||
assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: difficulty test
|
|
||||||
|
@ -159,11 +159,13 @@ macro_rules! evm_test_ignore(
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
|
#[cfg(feature = "ignored-tests")]
|
||||||
fn $name_jit() {
|
fn $name_jit() {
|
||||||
$name_test(Factory::new(VMType::Jit));
|
$name_test(Factory::new(VMType::Jit));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
|
#[cfg(feature = "ignored-tests")]
|
||||||
fn $name_int() {
|
fn $name_int() {
|
||||||
$name_test(Factory::new(VMType::Interpreter));
|
$name_test(Factory::new(VMType::Interpreter));
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,11 @@ pub struct Executed {
|
|||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
/// Gas used during execution of transaction.
|
/// Gas used during execution of transaction.
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
/// Gas refunded after the execution of transaction.
|
/// Gas refunded after the execution of transaction.
|
||||||
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
||||||
pub refunded: U256,
|
pub refunded: U256,
|
||||||
/// Cumulative gas used in current block so far.
|
/// Cumulative gas used in current block so far.
|
||||||
///
|
///
|
||||||
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
|
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
|
||||||
///
|
///
|
||||||
/// where `tn` is current transaction.
|
/// where `tn` is current transaction.
|
||||||
@ -56,9 +56,9 @@ pub struct Executed {
|
|||||||
pub logs: Vec<LogEntry>,
|
pub logs: Vec<LogEntry>,
|
||||||
/// Addresses of contracts created during execution of transaction.
|
/// Addresses of contracts created during execution of transaction.
|
||||||
/// Ordered from earliest creation.
|
/// Ordered from earliest creation.
|
||||||
///
|
///
|
||||||
/// eg. sender creates contract A and A in constructor creates contract B
|
/// eg. sender creates contract A and A in constructor creates contract B
|
||||||
///
|
///
|
||||||
/// B creation ends first, and it will be the first element of the vector.
|
/// B creation ends first, and it will be the first element of the vector.
|
||||||
pub contracts_created: Vec<Address>
|
pub contracts_created: Vec<Address>
|
||||||
}
|
}
|
||||||
@ -119,13 +119,13 @@ impl<'a> Executive<'a> {
|
|||||||
if t.nonce != nonce {
|
if t.nonce != nonce {
|
||||||
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
|
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate if transaction fits into given block
|
// validate if transaction fits into given block
|
||||||
if self.info.gas_used + t.gas > self.info.gas_limit {
|
if self.info.gas_used + t.gas > self.info.gas_limit {
|
||||||
return Err(From::from(ExecutionError::BlockGasLimitReached {
|
return Err(From::from(ExecutionError::BlockGasLimitReached {
|
||||||
gas_limit: self.info.gas_limit,
|
gas_limit: self.info.gas_limit,
|
||||||
gas_used: self.info.gas_used,
|
gas_used: self.info.gas_used,
|
||||||
gas: t.gas
|
gas: t.gas
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
if self.engine.is_builtin(¶ms.code_address) {
|
if self.engine.is_builtin(¶ms.code_address) {
|
||||||
// if destination is builtin, try to execute it
|
// if destination is builtin, try to execute it
|
||||||
|
|
||||||
let default = [];
|
let default = [];
|
||||||
let data = if let Some(ref d) = params.data { d as &[u8] } else { &default as &[u8] };
|
let data = if let Some(ref d) = params.data { d as &[u8] } else { &default as &[u8] };
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
} else if params.code.is_some() {
|
} else if params.code.is_some() {
|
||||||
// if destination is a contract, do normal message call
|
// if destination is a contract, do normal message call
|
||||||
|
|
||||||
// part of substate that may be reverted
|
// part of substate that may be reverted
|
||||||
let mut unconfirmed_substate = Substate::new();
|
let mut unconfirmed_substate = Substate::new();
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ impl<'a> Executive<'a> {
|
|||||||
Ok(params.gas)
|
Ok(params.gas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates contract with given contract params.
|
/// Creates contract with given contract params.
|
||||||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||||
/// Modifies the substate.
|
/// Modifies the substate.
|
||||||
@ -317,7 +317,7 @@ impl<'a> Executive<'a> {
|
|||||||
self.state.kill_account(address);
|
self.state.kill_account(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
@ -345,8 +345,8 @@ impl<'a> Executive<'a> {
|
|||||||
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
|
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
|
||||||
match *result {
|
match *result {
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
| Err(evm::Error::BadJumpDestination {..})
|
| Err(evm::Error::BadJumpDestination {..})
|
||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(evm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(evm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::OutOfStack {..}) => {
|
| Err(evm::Error::OutOfStack {..}) => {
|
||||||
self.state.revert_snapshot();
|
self.state.revert_snapshot();
|
||||||
@ -360,45 +360,14 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(dead_code)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use common::*;
|
use common::*;
|
||||||
use ethereum;
|
use evm::{Factory, VMType};
|
||||||
use engine::*;
|
|
||||||
use spec::*;
|
|
||||||
use evm::{Schedule, Factory, VMType};
|
|
||||||
use substate::*;
|
use substate::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
|
||||||
struct TestEngine {
|
|
||||||
factory: Factory,
|
|
||||||
spec: Spec,
|
|
||||||
max_depth: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestEngine {
|
|
||||||
fn new(max_depth: usize, factory: Factory) -> TestEngine {
|
|
||||||
TestEngine {
|
|
||||||
factory: factory,
|
|
||||||
spec: ethereum::new_frontier_test(),
|
|
||||||
max_depth: max_depth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Engine for TestEngine {
|
|
||||||
fn name(&self) -> &str { "TestEngine" }
|
|
||||||
fn spec(&self) -> &Spec { &self.spec }
|
|
||||||
fn vm_factory(&self) -> &Factory {
|
|
||||||
&self.factory
|
|
||||||
}
|
|
||||||
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
|
||||||
let mut schedule = Schedule::new_frontier();
|
|
||||||
schedule.max_depth = self.max_depth;
|
|
||||||
schedule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_contract_address() {
|
fn test_contract_address() {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
@ -487,7 +456,7 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.create(params, &mut substate).unwrap()
|
ex.create(params, &mut substate).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(62_976));
|
assert_eq!(gas_left, U256::from(62_976));
|
||||||
// ended with max depth
|
// ended with max depth
|
||||||
assert_eq!(substate.contracts_created.len(), 0);
|
assert_eq!(substate.contracts_created.len(), 0);
|
||||||
@ -541,7 +510,7 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.create(params, &mut substate).unwrap()
|
ex.create(params, &mut substate).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(62_976));
|
assert_eq!(gas_left, U256::from(62_976));
|
||||||
assert_eq!(substate.contracts_created.len(), 0);
|
assert_eq!(substate.contracts_created.len(), 0);
|
||||||
}
|
}
|
||||||
@ -593,12 +562,13 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.create(params, &mut substate).unwrap();
|
ex.create(params, &mut substate).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(substate.contracts_created.len(), 1);
|
assert_eq!(substate.contracts_created.len(), 1);
|
||||||
assert_eq!(substate.contracts_created[0], next_address);
|
assert_eq!(substate.contracts_created[0], next_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
|
// TODO: fix (preferred) or remove
|
||||||
evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int}
|
evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int}
|
||||||
fn test_aba_calls(factory: Factory) {
|
fn test_aba_calls(factory: Factory) {
|
||||||
// 60 00 - push 0
|
// 60 00 - push 0
|
||||||
@ -659,11 +629,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
|
// TODO: fix (preferred) or remove
|
||||||
evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int}
|
evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int}
|
||||||
fn test_recursive_bomb1(factory: Factory) {
|
fn test_recursive_bomb1(factory: Factory) {
|
||||||
// 60 01 - push 1
|
// 60 01 - push 1
|
||||||
// 60 00 - push 0
|
// 60 00 - push 0
|
||||||
// 54 - sload
|
// 54 - sload
|
||||||
// 01 - add
|
// 01 - add
|
||||||
// 60 00 - push 0
|
// 60 00 - push 0
|
||||||
// 55 - sstore
|
// 55 - sstore
|
||||||
@ -704,6 +675,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test is incorrect, mk
|
// test is incorrect, mk
|
||||||
|
// TODO: fix (preferred) or remove
|
||||||
evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int}
|
evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int}
|
||||||
fn test_transact_simple(factory: Factory) {
|
fn test_transact_simple(factory: Factory) {
|
||||||
let keypair = KeyPair::create().unwrap();
|
let keypair = KeyPair::create().unwrap();
|
||||||
@ -762,7 +734,7 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
ex.transact(&t)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (),
|
Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (),
|
||||||
_ => assert!(false, "Expected invalid signature error.")
|
_ => assert!(false, "Expected invalid signature error.")
|
||||||
@ -793,10 +765,10 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
ex.transact(&t)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got }))
|
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got }))
|
||||||
if expected == U256::zero() && got == U256::one() => (),
|
if expected == U256::zero() && got == U256::one() => (),
|
||||||
_ => assert!(false, "Expected invalid nonce error.")
|
_ => assert!(false, "Expected invalid nonce error.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -828,8 +800,8 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }))
|
Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }))
|
||||||
if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (),
|
if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (),
|
||||||
_ => assert!(false, "Expected block gas limit error.")
|
_ => assert!(false, "Expected block gas limit error.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -859,10 +831,10 @@ mod tests {
|
|||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
ex.transact(&t)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(Error::Execution(ExecutionError::NotEnoughCash { required , got }))
|
Err(Error::Execution(ExecutionError::NotEnoughCash { required , got }))
|
||||||
if required == U512::from(100_018) && got == U512::from(100_017) => (),
|
if required == U512::from(100_018) && got == U512::from(100_017) => (),
|
||||||
_ => assert!(false, "Expected not enough cash error. {:?}", res)
|
_ => assert!(false, "Expected not enough cash error. {:?}", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -902,5 +874,4 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,12 @@ pub struct Externalities<'a> {
|
|||||||
|
|
||||||
impl<'a> Externalities<'a> {
|
impl<'a> Externalities<'a> {
|
||||||
/// Basic `Externalities` constructor.
|
/// Basic `Externalities` constructor.
|
||||||
pub fn new(state: &'a mut State,
|
pub fn new(state: &'a mut State,
|
||||||
env_info: &'a EnvInfo,
|
env_info: &'a EnvInfo,
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
origin_info: OriginInfo,
|
origin_info: OriginInfo,
|
||||||
substate: &'a mut Substate,
|
substate: &'a mut Substate,
|
||||||
output: OutputPolicy<'a>) -> Self {
|
output: OutputPolicy<'a>) -> Self {
|
||||||
Externalities {
|
Externalities {
|
||||||
state: state,
|
state: state,
|
||||||
@ -106,16 +106,18 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn blockhash(&self, number: &U256) -> H256 {
|
fn blockhash(&self, number: &U256) -> H256 {
|
||||||
|
// TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent
|
||||||
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
|
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
|
||||||
true => {
|
true => {
|
||||||
let index = self.env_info.number - number.low_u64() - 1;
|
let index = self.env_info.number - number.low_u64() - 1;
|
||||||
|
assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1));
|
||||||
let r = self.env_info.last_hashes[index as usize].clone();
|
let r = self.env_info.last_hashes[index as usize].clone();
|
||||||
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
|
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
|
||||||
r
|
r
|
||||||
},
|
},
|
||||||
false => {
|
false => {
|
||||||
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
|
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
|
||||||
H256::from(&U256::zero())
|
H256::zero()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +141,7 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
|
|
||||||
self.state.inc_nonce(&self.origin_info.address);
|
self.state.inc_nonce(&self.origin_info.address);
|
||||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
|
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
|
||||||
|
|
||||||
// TODO: handle internal error separately
|
// TODO: handle internal error separately
|
||||||
match ex.create(params, self.substate) {
|
match ex.create(params, self.substate) {
|
||||||
Ok(gas_left) => {
|
Ok(gas_left) => {
|
||||||
@ -150,18 +152,18 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self,
|
fn call(&mut self,
|
||||||
gas: &U256,
|
gas: &U256,
|
||||||
sender_address: &Address,
|
sender_address: &Address,
|
||||||
receive_address: &Address,
|
receive_address: &Address,
|
||||||
value: Option<U256>,
|
value: Option<U256>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
code_address: &Address,
|
code_address: &Address,
|
||||||
output: &mut [u8]) -> MessageCallResult {
|
output: &mut [u8]) -> MessageCallResult {
|
||||||
|
|
||||||
let mut params = ActionParams {
|
let mut params = ActionParams {
|
||||||
sender: sender_address.clone(),
|
sender: sender_address.clone(),
|
||||||
address: receive_address.clone(),
|
address: receive_address.clone(),
|
||||||
value: ActionValue::Apparent(self.origin_info.value.clone()),
|
value: ActionValue::Apparent(self.origin_info.value.clone()),
|
||||||
code_address: code_address.clone(),
|
code_address: code_address.clone(),
|
||||||
origin: self.origin_info.origin.clone(),
|
origin: self.origin_info.origin.clone(),
|
||||||
@ -257,3 +259,144 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
|
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use common::*;
|
||||||
|
use state::*;
|
||||||
|
use engine::*;
|
||||||
|
use evm::{Ext};
|
||||||
|
use substate::*;
|
||||||
|
use tests::helpers::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn get_test_origin() -> OriginInfo {
|
||||||
|
OriginInfo {
|
||||||
|
address: Address::zero(),
|
||||||
|
origin: Address::zero(),
|
||||||
|
gas_price: U256::zero(),
|
||||||
|
value: U256::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_test_env_info() -> EnvInfo {
|
||||||
|
EnvInfo {
|
||||||
|
number: 100,
|
||||||
|
author: x!(0),
|
||||||
|
timestamp: 0,
|
||||||
|
difficulty: x!(0),
|
||||||
|
last_hashes: vec![],
|
||||||
|
gas_used: x!(0),
|
||||||
|
gas_limit: x!(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestSetup {
|
||||||
|
state: GuardedTempResult<State>,
|
||||||
|
engine: Box<Engine>,
|
||||||
|
sub_state: Substate,
|
||||||
|
env_info: EnvInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSetup {
|
||||||
|
fn new() -> TestSetup {
|
||||||
|
TestSetup {
|
||||||
|
state: get_temp_state(),
|
||||||
|
engine: get_test_spec().to_engine().unwrap(),
|
||||||
|
sub_state: Substate::new(),
|
||||||
|
env_info: get_test_env_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_be_created() {
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
|
||||||
|
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
|
||||||
|
assert_eq!(ext.env_info().number, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_return_block_hash_no_env() {
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
|
||||||
|
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
||||||
|
|
||||||
|
assert_eq!(hash, H256::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_return_block_hash() {
|
||||||
|
let test_hash = H256::from("afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd");
|
||||||
|
let test_env_number = 0x120001;
|
||||||
|
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
{
|
||||||
|
let env_info = &mut setup.env_info;
|
||||||
|
env_info.number = test_env_number;
|
||||||
|
env_info.last_hashes.push(test_hash.clone());
|
||||||
|
}
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
|
||||||
|
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
||||||
|
|
||||||
|
assert_eq!(test_hash, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn can_call_fail_empty() {
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
|
||||||
|
let mut output = vec![];
|
||||||
|
|
||||||
|
// this should panic because we have no balance on any account
|
||||||
|
ext.call(
|
||||||
|
&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap(),
|
||||||
|
&Address::new(),
|
||||||
|
&Address::new(),
|
||||||
|
Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()),
|
||||||
|
&vec![],
|
||||||
|
&Address::new(),
|
||||||
|
&mut output);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_log() {
|
||||||
|
let log_data = vec![120u8, 110u8];
|
||||||
|
let log_topics = vec![H256::from("af0fa234a6af46afa23faf23bcbc1c1cb4bcb7bcbe7e7e7ee3ee2edddddddddd")];
|
||||||
|
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
ext.log(log_topics, &log_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(setup.sub_state.logs.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_suicide() {
|
||||||
|
let refund_account = &Address::new();
|
||||||
|
|
||||||
|
let mut setup = TestSetup::new();
|
||||||
|
let state = setup.state.reference_mut();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract);
|
||||||
|
ext.suicide(&refund_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(setup.sub_state.suicides.len(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -260,7 +260,7 @@ pub struct TransactionAddress {
|
|||||||
/// Block hash
|
/// Block hash
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
/// Transaction index within the block
|
/// Transaction index within the block
|
||||||
pub index: u64
|
pub index: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtrasIndexable for TransactionAddress {
|
impl ExtrasIndexable for TransactionAddress {
|
||||||
|
@ -26,29 +26,29 @@ use externalities::*;
|
|||||||
use substate::*;
|
use substate::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
|
||||||
struct TestEngine {
|
struct TestEngineFrontier {
|
||||||
vm_factory: Factory,
|
vm_factory: Factory,
|
||||||
spec: Spec,
|
spec: Spec,
|
||||||
max_depth: usize
|
max_depth: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestEngine {
|
impl TestEngineFrontier {
|
||||||
fn new(max_depth: usize, vm_type: VMType) -> TestEngine {
|
fn new(max_depth: usize, vm_type: VMType) -> TestEngineFrontier {
|
||||||
TestEngine {
|
TestEngineFrontier {
|
||||||
vm_factory: Factory::new(vm_type),
|
vm_factory: Factory::new(vm_type),
|
||||||
spec: ethereum::new_frontier_test(),
|
spec: ethereum::new_frontier_test(),
|
||||||
max_depth: max_depth
|
max_depth: max_depth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine for TestEngine {
|
impl Engine for TestEngineFrontier {
|
||||||
fn name(&self) -> &str { "TestEngine" }
|
fn name(&self) -> &str { "TestEngine" }
|
||||||
fn spec(&self) -> &Spec { &self.spec }
|
fn spec(&self) -> &Spec { &self.spec }
|
||||||
fn vm_factory(&self) -> &Factory { &self.vm_factory }
|
fn vm_factory(&self) -> &Factory { &self.vm_factory }
|
||||||
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
||||||
let mut schedule = Schedule::new_frontier();
|
let mut schedule = Schedule::new_frontier();
|
||||||
schedule.max_depth = self.max_depth;
|
schedule.max_depth = self.max_depth;
|
||||||
schedule
|
schedule
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,12 +69,12 @@ struct TestExt<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TestExt<'a> {
|
impl<'a> TestExt<'a> {
|
||||||
fn new(state: &'a mut State,
|
fn new(state: &'a mut State,
|
||||||
info: &'a EnvInfo,
|
info: &'a EnvInfo,
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
origin_info: OriginInfo,
|
origin_info: OriginInfo,
|
||||||
substate: &'a mut Substate,
|
substate: &'a mut Substate,
|
||||||
output: OutputPolicy<'a>,
|
output: OutputPolicy<'a>,
|
||||||
address: Address) -> Self {
|
address: Address) -> Self {
|
||||||
TestExt {
|
TestExt {
|
||||||
@ -116,13 +116,13 @@ impl<'a> Ext for TestExt<'a> {
|
|||||||
ContractCreateResult::Created(self.contract_address.clone(), *gas)
|
ContractCreateResult::Created(self.contract_address.clone(), *gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self,
|
fn call(&mut self,
|
||||||
gas: &U256,
|
gas: &U256,
|
||||||
_sender_address: &Address,
|
_sender_address: &Address,
|
||||||
receive_address: &Address,
|
receive_address: &Address,
|
||||||
value: Option<U256>,
|
value: Option<U256>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
_code_address: &Address,
|
_code_address: &Address,
|
||||||
_output: &mut [u8]) -> MessageCallResult {
|
_output: &mut [u8]) -> MessageCallResult {
|
||||||
self.callcreates.push(CallCreate {
|
self.callcreates.push(CallCreate {
|
||||||
data: data.to_vec(),
|
data: data.to_vec(),
|
||||||
@ -136,7 +136,7 @@ impl<'a> Ext for TestExt<'a> {
|
|||||||
fn extcode(&self, address: &Address) -> Bytes {
|
fn extcode(&self, address: &Address) -> Bytes {
|
||||||
self.ext.extcode(address)
|
self.ext.extcode(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
|
||||||
self.ext.log(topics, data)
|
self.ext.log(topics, data)
|
||||||
}
|
}
|
||||||
@ -185,11 +185,11 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
// ::std::io::stdout().flush();
|
// ::std::io::stdout().flush();
|
||||||
let mut fail = false;
|
let mut fail = false;
|
||||||
//let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true };
|
//let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true };
|
||||||
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
|
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
|
||||||
failed.push(format!("[{}] {}: {}", vm, name, s));
|
failed.push(format!("[{}] {}: {}", vm, name, s));
|
||||||
fail = true
|
fail = true
|
||||||
};
|
};
|
||||||
|
|
||||||
// test env
|
// test env
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
@ -209,7 +209,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
EnvInfo::from_json(env)
|
EnvInfo::from_json(env)
|
||||||
}).unwrap_or_default();
|
}).unwrap_or_default();
|
||||||
|
|
||||||
let engine = TestEngine::new(1, vm.clone());
|
let engine = TestEngineFrontier::new(1, vm.clone());
|
||||||
|
|
||||||
// params
|
// params
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
@ -226,18 +226,18 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
|
|
||||||
let out_of_gas = test.find("callcreates").map(|_calls| {
|
let out_of_gas = test.find("callcreates").map(|_calls| {
|
||||||
}).is_none();
|
}).is_none();
|
||||||
|
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
let (res, callcreates) = {
|
let (res, callcreates) = {
|
||||||
let mut ex = TestExt::new(&mut state,
|
let mut ex = TestExt::new(&mut state,
|
||||||
&info,
|
&info,
|
||||||
&engine,
|
&engine,
|
||||||
0,
|
0,
|
||||||
OriginInfo::from(¶ms),
|
OriginInfo::from(¶ms),
|
||||||
&mut substate,
|
&mut substate,
|
||||||
OutputPolicy::Return(BytesRef::Flexible(&mut output)),
|
OutputPolicy::Return(BytesRef::Flexible(&mut output)),
|
||||||
params.address.clone());
|
params.address.clone());
|
||||||
let evm = engine.vm_factory().create();
|
let evm = engine.vm_factory().create();
|
||||||
|
@ -20,7 +20,6 @@ mod test_common;
|
|||||||
mod transaction;
|
mod transaction;
|
||||||
mod executive;
|
mod executive;
|
||||||
mod state;
|
mod state;
|
||||||
mod client;
|
|
||||||
mod chain;
|
mod chain;
|
||||||
mod homestead_state;
|
mod homestead_state;
|
||||||
mod homestead_chain;
|
mod homestead_chain;
|
||||||
|
@ -56,6 +56,12 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn created() {
|
||||||
|
let sub_state = Substate::new();
|
||||||
|
assert_eq!(sub_state.suicides.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn accrue() {
|
fn accrue() {
|
||||||
let mut sub_state = Substate::new();
|
let mut sub_state = Substate::new();
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use client::{BlockChainClient,Client};
|
use client::{BlockChainClient,Client};
|
||||||
use super::test_common::*;
|
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn created() {
|
fn created() {
|
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
use client::{BlockChainClient, Client};
|
use client::{BlockChainClient, Client};
|
||||||
use std::env;
|
use std::env;
|
||||||
use common::*;
|
use common::*;
|
||||||
@ -24,7 +23,9 @@ use std::fs::{remove_dir_all};
|
|||||||
use blockchain::{BlockChain};
|
use blockchain::{BlockChain};
|
||||||
use state::*;
|
use state::*;
|
||||||
use rocksdb::*;
|
use rocksdb::*;
|
||||||
|
use evm::{Schedule, Factory};
|
||||||
|
use engine::*;
|
||||||
|
use ethereum;
|
||||||
|
|
||||||
#[cfg(feature = "json-tests")]
|
#[cfg(feature = "json-tests")]
|
||||||
pub enum ChainEra {
|
pub enum ChainEra {
|
||||||
@ -82,6 +83,35 @@ impl<T> GuardedTempResult<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TestEngine {
|
||||||
|
factory: Factory,
|
||||||
|
spec: Spec,
|
||||||
|
max_depth: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestEngine {
|
||||||
|
pub fn new(max_depth: usize, factory: Factory) -> TestEngine {
|
||||||
|
TestEngine {
|
||||||
|
factory: factory,
|
||||||
|
spec: ethereum::new_frontier_test(),
|
||||||
|
max_depth: max_depth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine for TestEngine {
|
||||||
|
fn name(&self) -> &str { "TestEngine" }
|
||||||
|
fn spec(&self) -> &Spec { &self.spec }
|
||||||
|
fn vm_factory(&self) -> &Factory {
|
||||||
|
&self.factory
|
||||||
|
}
|
||||||
|
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
||||||
|
let mut schedule = Schedule::new_frontier();
|
||||||
|
schedule.max_depth = self.max_depth;
|
||||||
|
schedule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_test_spec() -> Spec {
|
pub fn get_test_spec() -> Spec {
|
||||||
Spec::new_test()
|
Spec::new_test()
|
||||||
}
|
}
|
||||||
@ -134,7 +164,6 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans
|
|||||||
rlp.out()
|
rlp.out()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> {
|
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> {
|
||||||
let dir = RandomTempPath::new();
|
let dir = RandomTempPath::new();
|
||||||
|
|
||||||
@ -174,7 +203,6 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> {
|
pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> {
|
||||||
let dir = RandomTempPath::new();
|
let dir = RandomTempPath::new();
|
||||||
let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
|
let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
|
||||||
@ -271,7 +299,6 @@ pub fn get_good_dummy_block() -> Bytes {
|
|||||||
create_test_block(&block_header)
|
create_test_block(&block_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "json-tests")]
|
|
||||||
pub fn get_bad_state_dummy_block() -> Bytes {
|
pub fn get_bad_state_dummy_block() -> Bytes {
|
||||||
let mut block_header = Header::new();
|
let mut block_header = Header::new();
|
||||||
let test_spec = get_test_spec();
|
let test_spec = get_test_spec();
|
||||||
|
@ -15,3 +15,4 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
mod client;
|
@ -20,7 +20,7 @@ use util::*;
|
|||||||
use error::*;
|
use error::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
/// Transaction action type.
|
/// Transaction action type.
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Create creates new contract.
|
/// Create creates new contract.
|
||||||
@ -45,7 +45,7 @@ impl Decodable for Action {
|
|||||||
|
|
||||||
/// A set of information describing an externally-originating message call
|
/// A set of information describing an externally-originating message call
|
||||||
/// or contract creation operation.
|
/// or contract creation operation.
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// Nonce.
|
/// Nonce.
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
@ -158,7 +158,7 @@ impl Transaction {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct SignedTransaction {
|
pub struct SignedTransaction {
|
||||||
/// Plain Transaction.
|
/// Plain Transaction.
|
||||||
unsigned: Transaction,
|
unsigned: Transaction,
|
||||||
@ -174,6 +174,12 @@ pub struct SignedTransaction {
|
|||||||
sender: RefCell<Option<Address>>
|
sender: RefCell<Option<Address>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for SignedTransaction {
|
||||||
|
fn eq(&self, other: &SignedTransaction) -> bool {
|
||||||
|
self.unsigned == other.unsigned && self.v == other.v && self.r == other.r && self.s == other.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for SignedTransaction {
|
impl Deref for SignedTransaction {
|
||||||
type Target = Transaction;
|
type Target = Transaction;
|
||||||
|
|
||||||
|
@ -294,6 +294,10 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_address(&self, _hash: &H256) -> Option<TransactionAddress> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the hash of given block's number.
|
/// Get the hash of given block's number.
|
||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
||||||
self.numbers.get(&index).cloned()
|
self.numbers.get(&index).cloned()
|
||||||
|
@ -155,6 +155,11 @@ impl<'a> BlockView<'a> {
|
|||||||
self.rlp.val_at(1)
|
self.rlp.val_at(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return number of transactions in given block, without deserializing them.
|
||||||
|
pub fn transactions_count(&self) -> usize {
|
||||||
|
self.rlp.at(1).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
||||||
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
||||||
@ -170,6 +175,11 @@ impl<'a> BlockView<'a> {
|
|||||||
self.rlp.val_at(2)
|
self.rlp.val_at(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return number of uncles in given block, without deserializing them.
|
||||||
|
pub fn uncles_count(&self) -> usize {
|
||||||
|
self.rlp.at(2).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
||||||
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_0.9.0-0_amd64.deb
|
PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_linux_0.9.0-0_amd64.deb
|
||||||
|
|
||||||
|
|
||||||
function run_installer()
|
function run_installer()
|
||||||
@ -47,6 +47,7 @@ function run_installer()
|
|||||||
dim=`tput dim`
|
dim=`tput dim`
|
||||||
reverse=`tput rev`
|
reverse=`tput rev`
|
||||||
reset=`tput sgr0`
|
reset=`tput sgr0`
|
||||||
|
n=$'\n'
|
||||||
|
|
||||||
|
|
||||||
function head() {
|
function head() {
|
||||||
@ -94,13 +95,19 @@ function run_installer()
|
|||||||
####### Setup methods
|
####### Setup methods
|
||||||
|
|
||||||
function wait_for_user() {
|
function wait_for_user() {
|
||||||
|
if [[ $( ask_user "$1" ) == false ]]; then
|
||||||
|
abort_install "${red}==>${reset} Process stopped by user. To resume the install run the one-liner command again."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function ask_user() {
|
||||||
while :
|
while :
|
||||||
do
|
do
|
||||||
read -p "${blue}==>${reset} $1 [Y/n] " imp
|
read -p "${blue}==>${reset} $1 [Y/n] " imp
|
||||||
case $imp in
|
case $imp in
|
||||||
[yY] ) return 0; break ;;
|
[yY] ) echo true; break ;;
|
||||||
'' ) echo; break ;;
|
'' ) echo true; break ;;
|
||||||
[nN] ) return 1 ;;
|
[nN] ) echo false; break ;;
|
||||||
* ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'";
|
* ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'";
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@ -114,11 +121,19 @@ function run_installer()
|
|||||||
return
|
return
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
function exe() {
|
function exe() {
|
||||||
echo "\$ $@"; "$@"
|
echo "\$ $@"; "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sudo() {
|
||||||
|
if $isSudo; then
|
||||||
|
`which sudo` "$@"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function detectOS() {
|
function detectOS() {
|
||||||
if [[ "$OSTYPE" == "linux-gnu" ]]
|
if [[ "$OSTYPE" == "linux-gnu" ]]
|
||||||
then
|
then
|
||||||
@ -130,7 +145,7 @@ function run_installer()
|
|||||||
get_osx_dependencies
|
get_osx_dependencies
|
||||||
else
|
else
|
||||||
OS_TYPE="win"
|
OS_TYPE="win"
|
||||||
abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.\nFor instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}"
|
abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.${n}For instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
@ -184,8 +199,8 @@ function run_installer()
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.\n"
|
errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.${n}"
|
||||||
errorMessages+=" Please update the OS and reload the install process.\n"
|
errorMessages+=" Please update the OS and reload the install process.${n}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_osx_dependencies()
|
function get_osx_dependencies()
|
||||||
@ -201,16 +216,19 @@ function run_installer()
|
|||||||
source /etc/lsb-release
|
source /etc/lsb-release
|
||||||
|
|
||||||
if [[ $DISTRIB_ID == "Ubuntu" ]]; then
|
if [[ $DISTRIB_ID == "Ubuntu" ]]; then
|
||||||
if [[ $DISTRIB_RELEASE == "14.04" ]]; then
|
if [[ $DISTRIB_RELEASE == "14.04" || $DISTRIB_RELEASE == "15.04" || $DISTRIB_RELEASE == "15.10" ]]; then
|
||||||
check "Ubuntu-14.04"
|
check "Ubuntu"
|
||||||
isUbuntu1404=true
|
isUbuntu=true
|
||||||
else
|
else
|
||||||
check "Ubuntu, but not 14.04"
|
check "Ubuntu, but version not supported"
|
||||||
isUbuntu1404=false
|
|
||||||
|
errorMessages+="${red}==>${reset} ${b}Ubuntu version not supported:${reset} This script requires Ubuntu version 14.04, 15.04 or 15.10.${n}"
|
||||||
|
errorMessages+=" Please either upgrade your Ubuntu installation or using the get-deps.ethcore.io script instead, which can help you build Parity.${n}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
check "Ubuntu not found"
|
check "Ubuntu not found"
|
||||||
isUbuntu1404=false
|
errorMessages+="${red}==>${reset} ${b}Linux distribution not supported:${reset} This script requires Ubuntu version 14.04, 15.04 or 15.10.${n}"
|
||||||
|
errorMessages+=" Please either use this on an Ubuntu installation or instead use the get-deps.ethcore.io script, which can help you build Parity.${n}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,15 +236,12 @@ function run_installer()
|
|||||||
{
|
{
|
||||||
linux_version
|
linux_version
|
||||||
|
|
||||||
find_multirust
|
|
||||||
find_rocksdb
|
find_rocksdb
|
||||||
|
|
||||||
find_curl
|
find_curl
|
||||||
find_git
|
|
||||||
find_make
|
|
||||||
find_gcc
|
|
||||||
|
|
||||||
find_apt
|
find_apt
|
||||||
|
find_sudo
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_brew()
|
function find_brew()
|
||||||
@ -242,10 +257,10 @@ function run_installer()
|
|||||||
uncheck "Homebrew is missing"
|
uncheck "Homebrew is missing"
|
||||||
isBrew=false
|
isBrew=false
|
||||||
|
|
||||||
INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}\n"
|
INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}${n}"
|
||||||
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew\n"
|
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew${n}"
|
||||||
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library\n"
|
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library${n}"
|
||||||
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1\n"
|
INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1${n}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
depCount=$((depCount+1))
|
depCount=$((depCount+1))
|
||||||
@ -267,11 +282,57 @@ function run_installer()
|
|||||||
uncheck "Ruby is missing 🔥"
|
uncheck "Ruby is missing 🔥"
|
||||||
isRuby=false
|
isRuby=false
|
||||||
canContinue=false
|
canContinue=false
|
||||||
errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.\n"
|
errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.${n}"
|
||||||
errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.\n"
|
errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.${n}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function find_sudo()
|
||||||
|
{
|
||||||
|
depCount=$((depCount+1))
|
||||||
|
SUDO_PATH=`which sudo 2>/dev/null`
|
||||||
|
|
||||||
|
if [[ -f $SUDO_PATH ]]
|
||||||
|
then
|
||||||
|
depFound=$((depFound+1))
|
||||||
|
check "sudo"
|
||||||
|
isSudo=true
|
||||||
|
else
|
||||||
|
uncheck "sudo is missing"
|
||||||
|
if [[ `whoami` == "root" ]]; then
|
||||||
|
if [[ $isApt == false && $isMultirust == false ]]; then
|
||||||
|
canContinue=false
|
||||||
|
errorMessages+="${red}==>${reset} ${b}Couldn't find sudo:${reset} Sudo is needed for the installation of multirust.${n}"
|
||||||
|
errorMessages+=" Please ensure you have sudo installed or alternatively install multirust manually.${n}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
isSudo=false
|
||||||
|
INSTALL_FILES+="${blue}${dim}==>${reset}\tsudo${n}"
|
||||||
|
else
|
||||||
|
canContinue=false
|
||||||
|
errorMessages+="${red}==>${reset} ${b}Couldn't find sudo:${reset} Root access is needed for parts of this installation.${n}"
|
||||||
|
errorMessages+=" Please ensure you have sudo installed or alternatively run this script as root.${n}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function find_curl()
|
||||||
|
{
|
||||||
|
depCount=$((depCount+1))
|
||||||
|
CURL_PATH=`which curl 2>/dev/null`
|
||||||
|
|
||||||
|
if [[ -f $CURL_PATH ]]
|
||||||
|
then
|
||||||
|
depFound=$((depFound+1))
|
||||||
|
check "curl"
|
||||||
|
isCurl=true
|
||||||
|
else
|
||||||
|
uncheck "curl is missing"
|
||||||
|
isCurl=false
|
||||||
|
INSTALL_FILES+="${blue}${dim}==>${reset}\tcurl${n}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function find_rocksdb()
|
function find_rocksdb()
|
||||||
{
|
{
|
||||||
depCount=$((depCount+1))
|
depCount=$((depCount+1))
|
||||||
@ -282,33 +343,7 @@ function run_installer()
|
|||||||
else
|
else
|
||||||
uncheck "librocksdb is missing"
|
uncheck "librocksdb is missing"
|
||||||
isRocksDB=false
|
isRocksDB=false
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb\n"
|
INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb${n}"
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function find_multirust()
|
|
||||||
{
|
|
||||||
depCount=$((depCount+2))
|
|
||||||
MULTIRUST_PATH=`which multirust 2>/dev/null`
|
|
||||||
if [[ -f $MULTIRUST_PATH ]]; then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "multirust"
|
|
||||||
isMultirust=true
|
|
||||||
if [[ $(multirust show-default 2>/dev/null | grep nightly | wc -l) == 4 ]]; then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "rust nightly"
|
|
||||||
isMultirustNightly=true
|
|
||||||
else
|
|
||||||
uncheck "rust is not nightly"
|
|
||||||
isMultirustNightly=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tmultirust -> rust nightly\n"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
uncheck "multirust is missing"
|
|
||||||
uncheck "rust nightly is missing"
|
|
||||||
isMultirust=false
|
|
||||||
isMultirustNightly=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tmultirust\n"
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,112 +362,12 @@ function run_installer()
|
|||||||
uncheck "apt-get is missing"
|
uncheck "apt-get is missing"
|
||||||
isApt=false
|
isApt=false
|
||||||
|
|
||||||
if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then
|
canContinue=false
|
||||||
canContinue=false
|
errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.${n}"
|
||||||
errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.\n"
|
errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.${n}"
|
||||||
errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.\n"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_gcc()
|
|
||||||
{
|
|
||||||
depCount=$((depCount+1))
|
|
||||||
GCC_PATH=`which g++ 2>/dev/null`
|
|
||||||
|
|
||||||
if [[ -f $GCC_PATH ]]
|
|
||||||
then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "g++"
|
|
||||||
isGCC=true
|
|
||||||
else
|
|
||||||
uncheck "g++ is missing"
|
|
||||||
isGCC=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tg++\n"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function find_git()
|
|
||||||
{
|
|
||||||
depCount=$((depCount+1))
|
|
||||||
GIT_PATH=`which git 2>/dev/null`
|
|
||||||
|
|
||||||
if [[ -f $GIT_PATH ]]
|
|
||||||
then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "git"
|
|
||||||
isGit=true
|
|
||||||
else
|
|
||||||
uncheck "git is missing"
|
|
||||||
isGit=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tgit\n"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function find_make()
|
|
||||||
{
|
|
||||||
depCount=$((depCount+1))
|
|
||||||
MAKE_PATH=`which make 2>/dev/null`
|
|
||||||
|
|
||||||
if [[ -f $MAKE_PATH ]]
|
|
||||||
then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "make"
|
|
||||||
isMake=true
|
|
||||||
else
|
|
||||||
uncheck "make is missing"
|
|
||||||
isMake=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tmake\n"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function find_curl()
|
|
||||||
{
|
|
||||||
depCount=$((depCount+1))
|
|
||||||
CURL_PATH=`which curl 2>/dev/null`
|
|
||||||
|
|
||||||
if [[ -f $CURL_PATH ]]
|
|
||||||
then
|
|
||||||
depFound=$((depFound+1))
|
|
||||||
check "curl"
|
|
||||||
isCurl=true
|
|
||||||
else
|
|
||||||
uncheck "curl is missing"
|
|
||||||
isCurl=false
|
|
||||||
INSTALL_FILES+="${blue}${dim}==>${reset}\tcurl\n"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function ubuntu1404_rocksdb_installer()
|
|
||||||
{
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install -qq -y software-properties-common
|
|
||||||
sudo apt-add-repository -y ppa:giskou/librocksdb
|
|
||||||
sudo apt-get -f -y install
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install -qq -y librocksdb
|
|
||||||
}
|
|
||||||
|
|
||||||
function linux_rocksdb_installer()
|
|
||||||
{
|
|
||||||
if [[ $isUbuntu1404 == true ]]; then
|
|
||||||
ubuntu1404_rocksdb_installer
|
|
||||||
else
|
|
||||||
oldpwd=`pwd`
|
|
||||||
cd /tmp
|
|
||||||
exe git clone --branch v4.2 --depth=1 https://github.com/facebook/rocksdb.git
|
|
||||||
cd rocksdb
|
|
||||||
exe make shared_lib
|
|
||||||
sudo cp -a librocksdb.so* /usr/lib
|
|
||||||
sudo ldconfig
|
|
||||||
cd /tmp
|
|
||||||
rm -rf /tmp/rocksdb
|
|
||||||
cd $oldpwd
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function verify_installation()
|
function verify_installation()
|
||||||
{
|
{
|
||||||
ETH_PATH=`which parity 2>/dev/null`
|
ETH_PATH=`which parity 2>/dev/null`
|
||||||
@ -451,14 +386,10 @@ function run_installer()
|
|||||||
info "Verifying installation"
|
info "Verifying installation"
|
||||||
|
|
||||||
if [[ $OS_TYPE == "linux" ]]; then
|
if [[ $OS_TYPE == "linux" ]]; then
|
||||||
find_curl
|
|
||||||
find_git
|
|
||||||
find_make
|
|
||||||
find_gcc
|
|
||||||
find_rocksdb
|
find_rocksdb
|
||||||
find_multirust
|
find_apt
|
||||||
|
|
||||||
if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustNightly == false ]]; then
|
if [[ $isRocksDB == false || $isApt == false ]]; then
|
||||||
abortInstall
|
abortInstall
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -466,43 +397,29 @@ function run_installer()
|
|||||||
|
|
||||||
function linux_deps_installer()
|
function linux_deps_installer()
|
||||||
{
|
{
|
||||||
if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then
|
if [[ $isRocksDB == false || $isCurl == false ]]; then
|
||||||
info "Installing build dependencies..."
|
info "Preparing apt..."
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
if [[ $isGit == false ]]; then
|
|
||||||
sudo apt-get install -q -y git
|
|
||||||
fi
|
|
||||||
if [[ $isGCC == false ]]; then
|
|
||||||
sudo apt-get install -q -y g++ gcc
|
|
||||||
fi
|
|
||||||
if [[ $isMake == false ]]; then
|
|
||||||
sudo apt-get install -q -y make
|
|
||||||
fi
|
|
||||||
if [[ $isCurl == false ]]; then
|
|
||||||
sudo apt-get install -q -y curl
|
|
||||||
fi
|
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $isRocksDB == false ]]; then
|
if [[ $isRocksDB == false ]]; then
|
||||||
info "Installing rocksdb..."
|
info "Installing rocksdb..."
|
||||||
linux_rocksdb_installer
|
|
||||||
|
sudo apt-get install -qq -y software-properties-common
|
||||||
|
sudo apt-add-repository -y ppa:ethcore/ethcore
|
||||||
|
sudo apt-get -f -y install
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -qq -y librocksdb
|
||||||
|
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $isMultirust == false ]]; then
|
if [[ $isCurl == false ]]; then
|
||||||
info "Installing multirust..."
|
info "Installing curl..."
|
||||||
curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
|
sudo apt-get install -q -y curl
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $isMultirustNightly == false ]]; then
|
|
||||||
info "Installing rust nightly..."
|
|
||||||
sudo multirust update nightly
|
|
||||||
sudo multirust default nightly
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function linux_installer()
|
function linux_installer()
|
||||||
@ -513,7 +430,7 @@ function run_installer()
|
|||||||
info "Installing parity"
|
info "Installing parity"
|
||||||
file=/tmp/parity.deb
|
file=/tmp/parity.deb
|
||||||
|
|
||||||
wget $PARITY_DEB_URL -qO $file
|
curl -L $PARITY_DEB_URL > $file
|
||||||
sudo dpkg -i $file
|
sudo dpkg -i $file
|
||||||
rm $file
|
rm $file
|
||||||
}
|
}
|
||||||
@ -644,8 +561,8 @@ EOL
|
|||||||
{
|
{
|
||||||
echo
|
echo
|
||||||
successHeading "All done"
|
successHeading "All done"
|
||||||
# head "Next steps"
|
head "Next steps"
|
||||||
# info "Run ${cyan}\`\`${reset} to get started.${reset}"
|
info "Run ${cyan}\`parity -j\`${reset} to start the Parity Ethereum client.${reset}"
|
||||||
echo
|
echo
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@ -661,11 +578,9 @@ EOL
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#DEBUG
|
#DEBUG
|
||||||
|
|
||||||
|
|
||||||
head "${b}OK,${reset} let's install Parity now!"
|
head "${b}OK,${reset} let's install Parity now!"
|
||||||
if wait_for_user "${b}Last chance!${reset} Sure you want to install this software?"
|
if [[ $(ask_user "${b}Last chance!${reset} Sure you want to install this software?") == true ]]; then
|
||||||
then
|
|
||||||
install
|
install
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
@ -673,19 +588,12 @@ EOL
|
|||||||
finish
|
finish
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $OS_TYPE == "linux" && $DISTRIB_ID == "Ubuntu" ]]; then
|
||||||
|
if [[ $(ask_user "${b}Netstats${reset} Would you like to download, install and configure a Netstats client?${n}${b}${red}WARNING: ${reset}${red}This will need a secret and reconfigure any existing node/NPM installation you have.${reset} ") == true ]]; then
|
||||||
if [[ $OS_TYPE == "linux" ]]
|
|
||||||
then
|
|
||||||
echo "Netstats:"
|
|
||||||
head "Would you like to install and configure a netstats client?"
|
|
||||||
if wait_for_user "${b}OK,${reset} let's go!"
|
|
||||||
then
|
|
||||||
install_netstats
|
install_netstats
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Display goodbye message
|
# Display goodbye message
|
||||||
finish
|
finish
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ extern crate log as rlog;
|
|||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate ctrlc;
|
extern crate ctrlc;
|
||||||
extern crate fdlimit;
|
extern crate fdlimit;
|
||||||
|
extern crate target_info;
|
||||||
|
|
||||||
#[cfg(feature = "rpc")]
|
#[cfg(feature = "rpc")]
|
||||||
extern crate ethcore_rpc as rpc;
|
extern crate ethcore_rpc as rpc;
|
||||||
@ -40,24 +41,26 @@ use env_logger::LogBuilder;
|
|||||||
use ctrlc::CtrlC;
|
use ctrlc::CtrlC;
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::panics::MayPanic;
|
use util::panics::MayPanic;
|
||||||
|
use ethcore::spec::*;
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::service::{ClientService, NetSyncMessage};
|
use ethcore::service::{ClientService, NetSyncMessage};
|
||||||
use ethcore::ethereum;
|
use ethcore::ethereum;
|
||||||
use ethcore::spec;
|
use ethcore::spec;
|
||||||
use ethcore::blockchain::CacheSize;
|
use ethcore::blockchain::CacheSize;
|
||||||
use ethsync::EthSync;
|
use ethsync::EthSync;
|
||||||
|
use target_info::Target;
|
||||||
|
|
||||||
docopt!(Args derive Debug, "
|
docopt!(Args derive Debug, "
|
||||||
Parity. Ethereum Client.
|
Parity. Ethereum Client.
|
||||||
|
By Wood/Paronyan/Kotewicz/Drwięga/Volf.
|
||||||
|
Copyright 2015, 2016 Ethcore (UK) Limited
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
parity [options]
|
parity [options] [ <enode>... ]
|
||||||
parity [options] <enode>...
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-l --logging LOGGING Specify the logging level.
|
--chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file
|
||||||
-j --jsonrpc Enable the JSON-RPC API sever.
|
or frontier, mainnet, morden, or testnet [default: frontier].
|
||||||
--jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545].
|
|
||||||
|
|
||||||
--listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304].
|
--listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304].
|
||||||
--public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304].
|
--public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304].
|
||||||
@ -66,6 +69,11 @@ Options:
|
|||||||
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384].
|
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384].
|
||||||
--cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144].
|
--cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144].
|
||||||
|
|
||||||
|
-j --jsonrpc Enable the JSON-RPC API sever.
|
||||||
|
--jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545].
|
||||||
|
|
||||||
|
-l --logging LOGGING Specify the logging level.
|
||||||
|
-v --version Show information about version.
|
||||||
-h --help Show this screen.
|
-h --help Show this screen.
|
||||||
", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option<String>);
|
", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option<String>);
|
||||||
|
|
||||||
@ -109,7 +117,28 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_init_nodes(&self, spec: &spec::Spec) -> Vec<String> {
|
fn print_version() {
|
||||||
|
println!("\
|
||||||
|
Parity version {} ({}-{}-{})
|
||||||
|
Copyright 2015, 2016 Ethcore (UK) Limited
|
||||||
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||||
|
This is free software: you are free to change and redistribute it.
|
||||||
|
There is NO WARRANTY, to the extent permitted by law.
|
||||||
|
|
||||||
|
By Wood/Paronyan/Kotewicz/Drwięga/Volf.\
|
||||||
|
", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_spec() -> Spec {
|
||||||
|
match args.flag_chain.as_ref() {
|
||||||
|
"frontier" | "mainnet" => ethereum::new_frontier(),
|
||||||
|
"morden" | "testnet" => ethereum::new_morden(),
|
||||||
|
"olympic" => ethereum::new_olympic(),
|
||||||
|
f => Spec::from_json_utf8(contents(f).expect("Couldn't read chain specification file. Sure it exists?").as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_init_nodes(&self, spec: &Spec) -> Vec<String> {
|
||||||
match self.args.arg_enode.len() {
|
match self.args.arg_enode.len() {
|
||||||
0 => spec.nodes().clone(),
|
0 => spec.nodes().clone(),
|
||||||
_ => self.args.arg_enode.clone(),
|
_ => self.args.arg_enode.clone(),
|
||||||
@ -149,7 +178,12 @@ fn wait_for_exit(client: Arc<Client>) {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let conf = Configuration::parse();
|
let conf = Configuration::parse();
|
||||||
let spec = ethereum::new_frontier();
|
if conf.args.flag_version {
|
||||||
|
conf.print_version();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let spec = conf.get_spec();
|
||||||
|
|
||||||
// Setup logging
|
// Setup logging
|
||||||
setup_log(&conf.args.flag_logging);
|
setup_log(&conf.args.flag_logging);
|
||||||
|
@ -18,4 +18,4 @@ ethcore = { path = "../ethcore" }
|
|||||||
ethsync = { path = "../sync" }
|
ethsync = { path = "../sync" }
|
||||||
clippy = "0.0.37"
|
clippy = "0.0.37"
|
||||||
target_info = "0.1.0"
|
target_info = "0.1.0"
|
||||||
|
rustc-serialize = "0.3"
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#![plugin(serde_macros)]
|
#![plugin(serde_macros)]
|
||||||
#![plugin(clippy)]
|
#![plugin(clippy)]
|
||||||
|
|
||||||
|
extern crate rustc_serialize;
|
||||||
extern crate target_info;
|
extern crate target_info;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
@ -23,7 +23,7 @@ use util::sha3::*;
|
|||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::views::*;
|
use ethcore::views::*;
|
||||||
use v1::traits::{Eth, EthFilter};
|
use v1::traits::{Eth, EthFilter};
|
||||||
use v1::types::Block;
|
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus};
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient {
|
pub struct EthClient {
|
||||||
@ -40,6 +40,7 @@ impl EthClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Eth for EthClient {
|
impl Eth for EthClient {
|
||||||
|
// TODO: do not hardcode protocol version
|
||||||
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => Ok(Value::U64(63)),
|
Params::None => Ok(Value::U64(63)),
|
||||||
@ -47,6 +48,15 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: do no hardcode default sync status
|
||||||
|
fn syncing(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => to_value(&SyncStatus::default()),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do not hardcode author.
|
||||||
fn author(&self, params: Params) -> Result<Value, Error> {
|
fn author(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&Address::new()),
|
Params::None => to_value(&Address::new()),
|
||||||
@ -54,6 +64,23 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: return real value of mining once it's implemented.
|
||||||
|
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => Ok(Value::Bool(false)),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: return real hashrate once we have mining
|
||||||
|
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => Ok(Value::U64(0)),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do not hardode gas_price
|
||||||
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => Ok(Value::U64(0)),
|
Params::None => Ok(Value::U64(0)),
|
||||||
@ -68,27 +95,37 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
fn block_transaction_count(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match from_params::<H256>(params) {
|
||||||
Params::None => Ok(Value::Bool(false)),
|
Ok(hash) => match self.client.block(&hash) {
|
||||||
_ => Err(Error::invalid_params())
|
Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()),
|
||||||
|
None => Ok(Value::Null)
|
||||||
|
},
|
||||||
|
Err(err) => Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
fn block_uncles_count(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match from_params::<H256>(params) {
|
||||||
Params::None => Ok(Value::U64(0)),
|
Ok(hash) => match self.client.block(&hash) {
|
||||||
_ => Err(Error::invalid_params())
|
Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()),
|
||||||
|
None => Ok(Value::Null)
|
||||||
|
},
|
||||||
|
Err(err) => Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_transaction_count(&self, _: Params) -> Result<Value, Error> {
|
// TODO: do not ignore block number param
|
||||||
Ok(Value::U64(0))
|
fn code_at(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match from_params::<(Address, BlockNumber)>(params) {
|
||||||
|
Ok((address, _block_number)) => to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new)),
|
||||||
|
Err(err) => Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, params: Params) -> Result<Value, Error> {
|
fn block(&self, params: Params) -> Result<Value, Error> {
|
||||||
match from_params::<(H256, bool)>(params) {
|
match from_params::<(H256, bool)>(params) {
|
||||||
Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) {
|
Ok((hash, include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) {
|
||||||
(Some(bytes), Some(total_difficulty)) => {
|
(Some(bytes), Some(total_difficulty)) => {
|
||||||
let view = HeaderView::new(&bytes);
|
let view = HeaderView::new(&bytes);
|
||||||
let block = Block {
|
let block = Block {
|
||||||
@ -108,7 +145,14 @@ impl Eth for EthClient {
|
|||||||
difficulty: view.difficulty(),
|
difficulty: view.difficulty(),
|
||||||
total_difficulty: total_difficulty,
|
total_difficulty: total_difficulty,
|
||||||
uncles: vec![],
|
uncles: vec![],
|
||||||
transactions: vec![]
|
transactions: {
|
||||||
|
if include_txs {
|
||||||
|
BlockTransactions::Hashes(vec![])
|
||||||
|
} else {
|
||||||
|
BlockTransactions::Full(vec![])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extra_data: Bytes::default()
|
||||||
};
|
};
|
||||||
to_value(&block)
|
to_value(&block)
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
pub mod traits;
|
pub mod traits;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod types;
|
mod types;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
pub use self::traits::{Web3, Eth, EthFilter, Net};
|
pub use self::traits::{Web3, Eth, EthFilter, Net};
|
||||||
pub use self::impls::*;
|
pub use self::impls::*;
|
||||||
|
1
rpc/src/v1/tests/mod.rs
Normal file
1
rpc/src/v1/tests/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
//TODO: load custom blockchain state and test
|
@ -23,6 +23,9 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
/// Returns protocol version.
|
/// Returns protocol version.
|
||||||
fn protocol_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn protocol_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns an object with data about the sync status or false. (wtf?)
|
||||||
|
fn syncing(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
/// Returns the number of hashes per second that the node is mining with.
|
/// Returns the number of hashes per second that the node is mining with.
|
||||||
fn hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
@ -108,6 +111,7 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
fn to_delegate(self) -> IoDelegate<Self> {
|
||||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||||
delegate.add_method("eth_protocolVersion", Eth::protocol_version);
|
delegate.add_method("eth_protocolVersion", Eth::protocol_version);
|
||||||
|
delegate.add_method("eth_syncing", Eth::syncing);
|
||||||
delegate.add_method("eth_hashrate", Eth::hashrate);
|
delegate.add_method("eth_hashrate", Eth::hashrate);
|
||||||
delegate.add_method("eth_coinbase", Eth::author);
|
delegate.add_method("eth_coinbase", Eth::author);
|
||||||
delegate.add_method("eth_mining", Eth::is_mining);
|
delegate.add_method("eth_mining", Eth::is_mining);
|
||||||
|
@ -14,10 +14,28 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::uint::*;
|
use util::uint::*;
|
||||||
|
use v1::types::{Bytes, Transaction};
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
pub enum BlockTransactions {
|
||||||
|
Hashes(Vec<H256>),
|
||||||
|
Full(Vec<Transaction>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for BlockTransactions {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer {
|
||||||
|
match *self {
|
||||||
|
BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer),
|
||||||
|
BlockTransactions::Full(ref ts) => ts.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
#[serde(rename="parentHash")]
|
#[serde(rename="parentHash")]
|
||||||
@ -38,9 +56,8 @@ pub struct Block {
|
|||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
#[serde(rename="gasLimit")]
|
#[serde(rename="gasLimit")]
|
||||||
pub gas_limit: U256,
|
pub gas_limit: U256,
|
||||||
// TODO: figure out how to properly serialize bytes
|
#[serde(rename="extraData")]
|
||||||
//#[serde(rename="extraData")]
|
pub extra_data: Bytes,
|
||||||
//extra_data: Vec<u8>,
|
|
||||||
#[serde(rename="logsBloom")]
|
#[serde(rename="logsBloom")]
|
||||||
pub logs_bloom: H2048,
|
pub logs_bloom: H2048,
|
||||||
pub timestamp: U256,
|
pub timestamp: U256,
|
||||||
@ -48,5 +65,52 @@ pub struct Block {
|
|||||||
#[serde(rename="totalDifficulty")]
|
#[serde(rename="totalDifficulty")]
|
||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
pub uncles: Vec<U256>,
|
pub uncles: Vec<U256>,
|
||||||
pub transactions: Vec<U256>
|
pub transactions: BlockTransactions
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json;
|
||||||
|
use util::hash::*;
|
||||||
|
use util::uint::*;
|
||||||
|
use v1::types::{Transaction, Bytes};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_block_transactions() {
|
||||||
|
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#);
|
||||||
|
|
||||||
|
let t = BlockTransactions::Hashes(vec![H256::default()]);
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_block() {
|
||||||
|
let block = Block {
|
||||||
|
hash: H256::default(),
|
||||||
|
parent_hash: H256::default(),
|
||||||
|
uncles_hash: H256::default(),
|
||||||
|
author: Address::default(),
|
||||||
|
miner: Address::default(),
|
||||||
|
state_root: H256::default(),
|
||||||
|
transactions_root: H256::default(),
|
||||||
|
receipts_root: H256::default(),
|
||||||
|
number: U256::default(),
|
||||||
|
gas_used: U256::default(),
|
||||||
|
gas_limit: U256::default(),
|
||||||
|
extra_data: Bytes::default(),
|
||||||
|
logs_bloom: H2048::default(),
|
||||||
|
timestamp: U256::default(),
|
||||||
|
difficulty: U256::default(),
|
||||||
|
total_difficulty: U256::default(),
|
||||||
|
uncles: vec![],
|
||||||
|
transactions: BlockTransactions::Hashes(vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&block).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x00","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","uncles":[],"transactions":[]}"#);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
68
rpc/src/v1/types/block_number.rs
Normal file
68
rpc/src/v1/types/block_number.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Error};
|
||||||
|
use serde::de::Visitor;
|
||||||
|
|
||||||
|
/// Represents rpc api block number param.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum BlockNumber {
|
||||||
|
Num(u64),
|
||||||
|
Latest,
|
||||||
|
Earliest,
|
||||||
|
Pending
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for BlockNumber {
|
||||||
|
fn deserialize<D>(deserializer: &mut D) -> Result<BlockNumber, D::Error>
|
||||||
|
where D: Deserializer {
|
||||||
|
deserializer.visit(BlockNumberVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BlockNumberVisitor;
|
||||||
|
|
||||||
|
impl Visitor for BlockNumberVisitor {
|
||||||
|
type Value = BlockNumber;
|
||||||
|
|
||||||
|
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: Error {
|
||||||
|
match value {
|
||||||
|
"latest" => Ok(BlockNumber::Latest),
|
||||||
|
"earliest" => Ok(BlockNumber::Earliest),
|
||||||
|
"pending" => Ok(BlockNumber::Pending),
|
||||||
|
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")),
|
||||||
|
_ => value.parse::<u64>().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: Error {
|
||||||
|
self.visit_str(value.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_number_deserialization() {
|
||||||
|
let s = r#"["0xa", "10", "latest", "earliest", "pending"]"#;
|
||||||
|
let deserialized: Vec<BlockNumber> = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
rpc/src/v1/types/bytes.rs
Normal file
61
rpc/src/v1/types/bytes.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use rustc_serialize::hex::ToHex;
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Wrapper structure around vector of bytes.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Bytes(Vec<u8>);
|
||||||
|
|
||||||
|
impl Bytes {
|
||||||
|
/// Simple constructor.
|
||||||
|
pub fn new(bytes: Vec<u8>) -> Bytes {
|
||||||
|
Bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Bytes {
|
||||||
|
fn default() -> Self {
|
||||||
|
// default serialized value is 0x00
|
||||||
|
Bytes(vec![0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Bytes {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer {
|
||||||
|
let mut serialized = "0x".to_owned();
|
||||||
|
serialized.push_str(self.0.to_hex().as_ref());
|
||||||
|
serializer.visit_str(serialized.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bytes_serialize() {
|
||||||
|
let bytes = Bytes("0123456789abcdef".from_hex().unwrap());
|
||||||
|
let serialized = serde_json::to_string(&bytes).unwrap();
|
||||||
|
assert_eq!(serialized, r#""0x0123456789abcdef""#);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -15,5 +15,13 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod block;
|
mod block;
|
||||||
|
mod block_number;
|
||||||
|
mod bytes;
|
||||||
|
mod sync;
|
||||||
|
mod transaction;
|
||||||
|
|
||||||
pub use self::block::Block;
|
pub use self::block::{Block, BlockTransactions};
|
||||||
|
pub use self::block_number::BlockNumber;
|
||||||
|
pub use self::bytes::Bytes;
|
||||||
|
pub use self::sync::SyncStatus;
|
||||||
|
pub use self::transaction::Transaction;
|
||||||
|
27
rpc/src/v1/types/sync.rs
Normal file
27
rpc/src/v1/types/sync.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use util::hash::*;
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize)]
|
||||||
|
pub struct SyncStatus {
|
||||||
|
#[serde(rename="startingBlock")]
|
||||||
|
pub starting_block: H256,
|
||||||
|
#[serde(rename="currentBlock")]
|
||||||
|
pub current_block: H256,
|
||||||
|
#[serde(rename="highestBlock")]
|
||||||
|
pub highest_block: H256,
|
||||||
|
}
|
52
rpc/src/v1/types/transaction.rs
Normal file
52
rpc/src/v1/types/transaction.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use util::hash::*;
|
||||||
|
use util::uint::*;
|
||||||
|
use v1::types::Bytes;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize)]
|
||||||
|
pub struct Transaction {
|
||||||
|
hash: H256,
|
||||||
|
nonce: U256,
|
||||||
|
#[serde(rename="blockHash")]
|
||||||
|
block_hash: H256,
|
||||||
|
#[serde(rename="blockNumber")]
|
||||||
|
block_number: U256,
|
||||||
|
#[serde(rename="transactionIndex")]
|
||||||
|
transaction_index: U256,
|
||||||
|
from: Address,
|
||||||
|
to: Address,
|
||||||
|
value: U256,
|
||||||
|
#[serde(rename="gasPrice")]
|
||||||
|
gas_price: U256,
|
||||||
|
gas: U256,
|
||||||
|
input: Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_serialize() {
|
||||||
|
let t = Transaction::default();
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
Some(U256::zero())
|
Some(U256::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn code(&self, _address: &Address) -> Option<Bytes> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn block_header(&self, h: &H256) -> Option<Bytes> {
|
fn block_header(&self, h: &H256) -> Option<Bytes> {
|
||||||
self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec())
|
self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec())
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! Diff misc.
|
//! Diff misc.
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
#[derive(Debug,Clone,PartialEq,Eq)]
|
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||||
@ -53,3 +54,11 @@ pub enum Filth {
|
|||||||
/// Data has been changed.
|
/// Data has been changed.
|
||||||
Dirty,
|
Dirty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the whole contents of a file `name`.
|
||||||
|
pub fn contents(name: &str) -> Result<Bytes, UtilError> {
|
||||||
|
let mut file = try!(File::open(name));
|
||||||
|
let mut ret: Vec<u8> = Vec::new();
|
||||||
|
try!(file.read_to_end(&mut ret));
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
@ -458,7 +458,8 @@ macro_rules! construct_uint {
|
|||||||
let mut hex = "0x".to_owned();
|
let mut hex = "0x".to_owned();
|
||||||
let mut bytes = [0u8; 8 * $n_words];
|
let mut bytes = [0u8; 8 * $n_words];
|
||||||
self.to_bytes(&mut bytes);
|
self.to_bytes(&mut bytes);
|
||||||
hex.push_str(bytes.to_hex().as_ref());
|
let len = cmp::max((self.bits() + 7) / 8, 1);
|
||||||
|
hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref());
|
||||||
serializer.visit_str(hex.as_ref())
|
serializer.visit_str(hex.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user