-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversion of EVM stack to big integers #137
Conversation
* no-git for publish jobs, empty artifacts dir (openethereum#10393) * no-git for publish jobs, empty artifacts dir * fix syntax * prettiness * fix prettiness * should get rid of git in publishing * Fix to_pod storage trie value decoding (openethereum#10368) * snap: reenable i386, arm64, armhf architecture publishing (openethereum#10386) * snap: reenable i386, arm64, armhf architecture publishing * gitlab: fix indent * gitlab: fix yml syntax * Linker for crosscomile * fix target to linker * new docker image * fix lint, add build to this PR * calc SHA3 using rhash * add new images for i386, armhf * show snap target & artifacts * set CARGO_TARGET for publish snap * move detect Version to publish snap * rm libc6 dep from snap-template up pub-snap script * clean up cargo config before add linker * move linker config to docker images
* revert some changes, could be buggy (openethereum#10399) * 10000 > 5000 (openethereum#10422) addresses openethereum#10418 * fix panic when logging directory does not exist, closes openethereum#10420 (openethereum#10424) * fix underflow in pip, closes openethereum#10419 (openethereum#10423) * ci: clean up gitlab-ci.yml leftovers from previous merge (openethereum#10429) * Update hardcoded headers for Foundation, Ropsten, Kovan and Classic (openethereum#10417) * update foundation to #7262209 * update kovan to #10434561 * update ropsten to #5027841 * update classic to #7555073 * Update Ropsten headers to #5101569
* version: bump beta * Implement parity_versionInfo & parity_setChain on LC; fix parity_setChain (openethereum#10312) * Light client: implement parity_versionInfo RPC * Light client: implement set_exit_handler & parity_setChain RPC * parity_setChain RPC: return an error if failed (instead of `true`) * Implement eth_subscribe('syncing') RPC for full node & light node * Fix indentation * Revert commit: Implement eth_subscribe('syncing') * Revert change to Cr callback function * CI publish to aws (openethereum#10446) * move publish aws from gitlab.yml to gitlab scripts * gitlab.yml cleaning move publish AWS to gitlab scripts remove dependencies from android build * CI aws git checkout (openethereum#10451) * Updating the CI system with the publication of releases and binary files on github Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com> * move publish aws from gitlab.yml to gitlab scripts Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com> * gitlab.yml cleaning move publish AWS to gitlab scripts remove dependencies from android build Signed-off-by: Denis S. Soldatov aka General-Beck <general.beck@gmail.com> * Revert "Updating the CI system with the publication of releases and binary files on github" This reverts commit da87e06. * remove no-git for aws * microfix * no need in no_git then * Revert "CI aws git checkout (openethereum#10451)" (openethereum#10456) * Revert "CI aws git checkout (openethereum#10451)" This reverts commit 3e1d731. * Update .gitlab-ci.yml revert aws script with small fixes * Delete publish-aws.sh * Tests parallelized (openethereum#10452) * tests splitted, phase 1 * typo * fix wrong launch commands * typos * rearrangements * use `nproc` function for threads * use nproc for threads * let theads be auto, build-andriod no more in regular run * split val chain and cargo check * renamed some files * wrong phase * check rust files before test jobs * lint error * rust files modivied var * test except changes * add rust_changes except * lint error * fixes * .gitlab-ci.yml can't be excluded * pipeline shouldn't start * pipeline must go * pipeline must go 2 * pipeline must go 3 * pipeline must go 4 * pipeline must go 5 * pipeline must go 6 * pipeline must go 7 * pipeline must not go 1 * pipeline must go 8 * avoid skippng tests yet, reintroducing them after the caching * test theory * parallelized cargo check with combusting helicopters * less uploads * alias for cargo checks * nice template * Ensure static validator set changes are recognized (openethereum#10467)
* version: bump beta * Сaching through docker volume (openethereum#10477) * _old codebase_ before docker update * before docker update, testing runnr * docker update, testing the caching * distributed job cargo homes * distributed job cargo homes 2 * distributed job cargo homes 3 * dockerfile with gitlab checkout, audit uses template * dockerfile gets repo in volume * change builds_dir * trying docker cache for repo * repo cached automatically * after script is not concatenated * check sccache non-cacheable reasons nature * watch cache * log sccache * log sccache 2 * debug log sccache * fix debug log sccache * fix debug log sccache 2 * debug log cache 3 * debug log cache 3 * trace log all sccache * test wo cargo cache * test w removed cargo cache * report non-cacheable reasons, cargo cache is back and empty * report non-cacheable reasons, cargo cache is back and empty 2 * report non-cacheable reasons, cargo cache is back and empty 3 * wrap into after_script * restore CI tags `qa` -> `linux-docker` * return to main runners, this will fail until config on runners And Dockerfile won't be updated * typo fix CI lint * return to docker tag * fix win&mac build (openethereum#10486) add CARGO_HOME: "${CI_PROJECT_DIR}/.cargo" * fix(extract `timestamp_checked_add` as lib) (openethereum#10383) * fix(extract `timestamp_checked_add` as lib) * fix(whisper types): remove unused `EmptyTopics` * fix(time-lib): feature-flag to use time-lib or std This commit adds conditional compilation checks that falls back to `our time-lib` when `time_checked_add` is not available in the standard library Note, `time_checked_add` covers both `checked_add` and `checked_sub` * fix(grumble): use cfg_attr to define rustc feature
* version: bump beta * Add additional request tests (openethereum#10503)
* version: bump beta * fix Sha3/keccak256 hash calculation for binaries (openethereum#10509) openethereum#10495 * verbose flag for cpp tests (openethereum#10524) * Initial support sccache for windows build (openethereum#10520) * Initial support sccache for win build * show sccache stats * cache paths for shared runners * sccache status is in the script. * removed windows test for now * ethcore: remove eth social and easthub chain configs (openethereum#10531) * Fix max_gas (openethereum#10537) Fix max_gas * build android with cache, win fixes (openethereum#10546) * build android with cache! * windows fixes * windows fixes 2 * windows fixes 3 * windows fixes 4 * windows should have sccache variables in env variables * Update light client harcoded headers (openethereum#10547) * kovan #10643457 * ropsten #5296129 * foundation #7460865 * classic #7747585 * indentation * morden #3973121
* fix(rpc-types): replace uint and hash with `ethereum_types v0.4` (openethereum#10217) * fix(rpc-types): remove uint and hash wrappers * fix(tests) * fix(cleanup) * grumbles(rpc-api): revert `verify_signature` * revert change of `U64` -> `u64` * fix(cleanup after bad merge) * chore(bump ethereum-types) * fix(bad merge) * feat(tests ethereum-types): add tests * chore(update `ethereum-types` to 0.4.2) * feat(tests for h256) * chore(rpc): remove `ethbloom` import Use re-export from `ethereum-types` instead * fix(bad merge): remove `DefaultAccount` type * doc(add TODO with issue link) * chore(bump ethereum-types) (openethereum#10396) Fixes a de-serialization bug in `ethereum-tyes` * fix(light eth_gasPrice): ask network if not in cache (openethereum#10535) * fix(light eth_gasPrice): ask N/W if not in cache * fix(bad rebase) * fix(light account response): update `tx_queue` (openethereum#10545) * fix(bump dependencies) (openethereum#10540) * cargo update -p log:0.4.5 * cargo update -p regex:1.0.5 * cargo update -p parking_lot * cargo update -p serde_derive * cargo update -p serde_json * cargo update -p serde * cargo update -p lazy_static * cargo update -p num_cpus * cargo update -p toml # Conflicts: # Cargo.lock * tx-pool: check transaction readiness before replacing (openethereum#10526) * Update to vanilla tx pool error * Prevent a non ready tx replacing a ready tx * Make tests compile * Test ready tx not replaced by future tx * Transaction indirection * Use StateReadiness to calculate Ready in `should_replace` * Test existing txs from same sender are used to compute Readiness * private-tx: Wire up ShouldReplace * Revert "Use StateReadiness to calculate Ready in `should_replace`" This reverts commit af9e69c * Make replace generic so it works with private-tx * Rename Replace and add missing docs * ShouldReplace no longer mutable * tx-pool: update to transaction-pool 2.0 from crates.io * tx-pool: generic error type alias * Exit early for first unmatching nonce * Fix private-tx test, use existing write lock * Use read lock for pool scoring * fix openethereum#10390 (openethereum#10391) * private-tx: replace error_chain (openethereum#10510) * Update to vanilla tx pool error * private-tx: remove error-chain, implement Error, derive Display * private-tx: replace ErrorKind and bail! * private-tx: add missing From impls and other compiler errors * private-tx: use original tx-pool error * Don't be silly cargo
* Add initial `engines::authority_round::randomness` module. * Added `authority_round_random.json`, based on `pos-contracts@8d10a85ad87633a54a7444883b32687faf5b80bf`. The contract was compiled using solc `0.4.25+commit.59dbf8f1.Linux.g++` and formatted using [json_pp](https://packages.debian.org/stretch/libjson-pp-perl). * Added phase skeleton for determination through constant contract calls. * Factor out utility functions into `util` module. * Add comments about adding txns to current block.
* Make calls service transactions i.e. zero gas price. * call reportMalicious with 0 gas price * call reportBenign with 0 gas price as well
`Engine::on_new_block` is called multiple times, so we need to remember which round a random secret is for, and generate a new one only in the following round. `on_block_new` also mustn't fail if the same transaction is produced again.
* WIP: store the encrypted secret on chain * Improve error handling * Aura randomness: Fix error handling. * Aura randomness: clean up and update comments. * Aura randomness: fix existing commit hash check
It is now called by the new method `ValidatorSet::on_new_block()`. Closes #71
These seem to be leftovers from debugging.
* Cleanup rand contract, add log for tx nonce error. The contract seems to have a duplicate entry. This replaces it with the generated ABI. `Client::transact` sometimes fails with and `Old` error, meaning the nonce is outdated. This will now just log an error instead of making block creation fail. The `schedule_service_transaction` method might get removed in the future anyway, if we make `ValidatorSet::on_new_block` _return_ the transaction instead of queueing it. * Fix error handling in on_prepare_block.
* Push validator set txns directly onto block. * Only call on_prepare_block on new blocks.
That solves the issue of the gas limit, where we'd otherwise pick some arbitrary large value, and the chain ID, which now conforms to EIP155 again.
I'll try to fully resync POA Sokol with new binary and see if any errors come up |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made google spreadsheet https://docs.google.com/spreadsheets/d/1Fa7pBG1vhwtPkQEBiFbjyWm_etWy2o1bVBHZYI3-zgA/edit?usp=sharing comparing the benchmark results for the commits:
- https://github.com/poanetwork/parity-ethereum/tree/0d3693aea3d0621722d01900a6894032167457f1
- https://github.com/poanetwork/parity-ethereum/tree/967b29e72f6a88ab309d913b8d73b8730ee78562
- https://github.com/poanetwork/parity-ethereum/tree/c159ba534613ea1a6f7f94deb5782884c5c35da8
It shows that the latest commit 0d3693a
is much slower than the commit c159ba5
made before refactoring (for all the benchmark tests).
The commit 0d3693a
is also slower than 967b29e
.
So, the current refactoring gives us the opposite results (slowing down from 1.1
to 2.8
times).
POA Core and xDai resynced without errors. In Sokol there was an error on block https://blockscout.com/poa/sokol/blocks/5021292/transactions (there's a single tx in that block).
Not sure if it's a real issue or just a bad block, I'll resync one more time. |
So is it this block on which resync failed? https://blockscout.com/poa/sokol/blocks/5021292/transactions |
Yes, it output the error message and stopped syncing. |
I think, testing these changes makes no sense because they slow down the node's work: #137 (review) We should test them when we see speed improvements in comparison with the |
Ok, please ping me when it's ready |
}, | ||
instructions::LOG0 | instructions::LOG1 | instructions::LOG2 | instructions::LOG3 | instructions::LOG4 => { | ||
let no_of_topics = instruction.log_topics().expect("log_topics always return some for LOG* instructions; qed"); | ||
let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics; | ||
|
||
let data_gas = overflowing!(Gas::from_u256(*stack.peek(1))?.overflow_mul(Gas::from(schedule.log_data_gas))); | ||
let data_gas = overflowing!(Gas::from_u256(integer_to_u256(stack.peek(1)))?.overflow_mul(Gas::from(schedule.log_data_gas))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it might be possible to multiply first, and convert later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conversion disappears if Gas = Integer
.
return Ok(Gas::from(0)); | ||
} | ||
|
||
Gas::from_u256(overflowing!(offset.overflowing_add(*size))) | ||
Gas::from_u256(overflowing!(integer_to_u256(offset).overflowing_add(integer_to_u256(size)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But even if CostType
is still only implemented for U256
and usize
, a Gas::from_integer
could speed up some of the conversions in this file, at least for usize
. And it would make the code less verbose.
if nel > 0 { | ||
// Fill out the leading zeros. | ||
self[offset..offset + nel].copy_from_slice(vec![0; nel].as_slice()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would avoid allocating a new vector of zeroes:
for byte in &mut self[offset..offset + nel] {
*byte = 0;
}
ethcore/evm/src/interpreter/mod.rs
Outdated
@@ -343,7 +337,8 @@ impl<Cost: CostType> Interpreter<Cost> { | |||
// Calculate gas cost | |||
let requirements = self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size())?; | |||
if self.do_trace { | |||
ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256(), Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)); | |||
let store_wr = Self::store_written(instruction, &self.stack).and_then(|(a, b)| Some((integer_to_u256(&a), integer_to_u256(&b)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and_then(|x| Some(f(x)))
is equivalent to map(|x| f(x))
.
ethcore/evm/src/interpreter/mod.rs
Outdated
} else { | ||
value << (shift.as_u32() as usize) | ||
value << shift.to_u32_wrapping() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be truncated to 256 bits?
ethcore/evm/src/interpreter/mod.rs
Outdated
let mut shifted = value >> shift; | ||
if sign { | ||
shifted = shifted | (U256::max_value() << (256 - shift)); | ||
shifted = shifted | (u256_max() << (256 - shift)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This creates a number with more than 256 bits.
Would shifted = shifted | (((1 << shift) - 1) << (256 - shift))
be correct?
Or would it be easier to apply two's complement above (instead of explicitly taking the sign), and apply it here again?
ethcore/evm/src/interpreter/mod.rs
Outdated
let sign = n.get_bit(255); | ||
let n_abs = if sign { | ||
// The result of addition cannot overflow 256 bits because the bit 255 is 0 after ^. | ||
(((Integer::from(1) << 256) - 1) ^ n) + 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2256 - 1 should probably also be a constant.
(Or would (Integer::from(1) << 256) - n
be just as fast?)
let digits = n256.to_digits::<u8>(Order::MsfBe); | ||
let len = digits.len(); | ||
r[SIZE - len .. SIZE].copy_from_slice(digits.as_slice()); | ||
r |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be deduplicated with integer_to_address
, using a helper method with a size
parameter.
Also, I wonder whether the allocation of n256
can be avoided by just using n.to_digits().as_slice()
directly, and copying only the required number of bytes? That shouldn't be too wasteful, since we probably only call these methods with numbers that have at most 32 bytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to store the intermediate vector n.to_digits()
anyway to refer to it as a slice but I'll try your suggestion.
#[inline] | ||
fn address_to_u256(value: Address) -> U256 { | ||
U256::from(&*H256::from(value)) | ||
fn apply_rug_first_signed_2<F>(f: F, a: Integer, b: Integer) -> Integer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to convert the result back if it's negative, either in all the call sites or in this method.
(Also in apply_rug_signed_2
.)
let (b, sign_b) = get_and_reset_sign(self.stack.pop_back()); | ||
|
||
// -2^255 | ||
let min = (U256::one() << 255) - U256::one(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This old code is rather puzzling because the constant here is in fact the maximum signed 256-bit integer (2 ** 255) - 1
, which is not what the comment claims it is (the precedence of the minus sign also requires extra parentheses in that comment). The minimum would have been just 1 << 255
equivalent to (-2) ** 255
. Therefore I removed the old clause that checked whether a
was the minimum integer because I think the implementation was incorrect. Moreover why would the minimum value of a
need to be mapped to itself? There is no such behaviour in the Jello Paper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this is weird. And b == !U256::zero()
is impossible anyway, isn't it? Because get_and_reset_sign
can't return numbers greater than 2255?
What the special case was meant to handle somehow was probably the fact that the two's complement of -2255 is -2255, so in that case a
would be 2255 (interpreted as unsigned). If you divide that by -1 (which is !U256::zero()
) the result is not representable, but the Yellow Paper says in that case we should return -2255. But I think we'd do that anyway, even in the last else
branch?
So probably the implementation is technically correct, because b == !U256::zero()
is impossible anyway?
I refactored the gasometer. Benchmarks report performance drop of 2-2.5 times with respect to the current |
As far as I understand, the main reason for slowness is |
What if we just do the same for instructions::MUL => {
let a = self.stack.pop_back();
let b = self.stack.pop_back();
self.stack.push(a.overflowing_mul(b).0);
}, try instructions::MUL => {
let a = self.stack.pop_back();
let b = self.stack.pop_back();
let a0 = Integer::from_digits(&a, Order::LsfLe);
let b0 = Integer::from_digits(&b, Order::LsfLe);
let r = a0 * b0;
self.stack.push(
U256::from_little_endian(r.to_digits::<u8>(Order::LsfLe).as_slice())
);
}, Did you try to do this for the |
Another thought: what if we leave the For all these tries we need to launch benchmarks to see whether it makes sense and for which size of operands. |
Yes. The places where the conversions happen matter. If any appear in the interpreter, it will run slower than if there weren't any conversions there. The place where conversions happen make difference to performance. Having conversions inside simple arithmetic opcode handlers (not complex like |
I converted the VM in 967b29e and performance regressed even more. Now it's 2.1-3.1 times slower than in |
I'd propose to leave our approach for MULMOD/ADDMOD with the Also, I'd propose to benchmark this one #137 (comment) and see if it is really slower than the standard U256. |
I suggested not using
Isn't this what I did in earlier commits? I used to convert from |
Ok, that would be interesting to compare Also, the solution with improving the
Yeah, I just didn't see the benchmark results for that comparison (or don't remember where they are in this repo). Maybe I'll try to compare that myself when I have time. |
I think you did benchmark that commit, 967b29e. I used a function |
FYI, the division algorithm in |
@ordian Thank you for the info! |
Closing in favour of #179. |
No description provided.