codechain-io / foundry Goto Github PK
View Code? Open in Web Editor NEWA programmable open source blockchain engine
License: GNU General Public License v3.0
A programmable open source blockchain engine
License: GNU General Public License v3.0
A node in Corgi spent about 10 seconds to import a term close block.
I am suspecting the trie performance.
See: CodeChain-io/codechain#970
Everytime we need to add a trait to Client, we have to make a pile of changes to trait bounds on Client. I think we need to simplify this.
After the CodeChain-io/codechain#1827, CodeChain has two sorts of minimum fees. One is defined by the network, the other is defined by each machine. For users not to confuse these new fee thresholds with common parameters, CodeChain needs a new RPC getting minimum fees configured by each machine.
Non-validator nodes don't execute transactions queued in the mempool and validator nodes don't propagate the information of a failed transaction.
In the user's point of view, who send an RPC to a non-validator node, a transaction rejected by validators remains in the mempool(it means mempool_getPendingTransactions
returns it) and there is no error hint so the users don't know it was rejected. Currently, the users have to send chain_executeTransaction
to know whether the transaction is valid or not.
We need a way to make non-validators exclude the failed transactions from their mempool.
The current implementation of body_downloader
imports a transaction only once, and the transaction can be rejected while importing to the mempool because of the mempool limit (memory limit or size limit). After being rejected, body_downloader
will never request them again.
Currently, all blocks are always verified before importing. However, there is no need to verify the seal when all the peers are trusted nodes. In this case, skipping verification of seals can improve block sync performance.
https://rr-project.org/
It records syscall to enable replayable debugging.
It has some limitations like emulating multicore, requiring performance monitor feature (not supported by VirtualBox, many types of AWS instances), but I think we can utilize it for our inner test server.
Each module will define its assets. We don't need to provide a general asset mechanism in Foundry.
types
miner
and rpc types
stack backtrace: [336/1846]
0: 0x55f9abd31575 - backtrace::backtrace::libunwind::trace::he919db7d4fe6588e
at /home/sgkim126/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.7/src/backtrace/libunwind.rs:53
- backtrace::backtrace::trace::h3519b7a75ace3a4b
at /home/sgkim126/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.7/src/backtrace/mod.rs:42
1: 0x55f9abd2c0fe - backtrace::capture::Backtrace::new_unresolved::h9582fd64c1dd4a71
at /home/sgkim126/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.7/src/capture.rs:88
2: 0x55f9abd2c03d - backtrace::capture::Backtrace::new::h09110bd3b1ec2d21
at /home/sgkim126/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.7/src/capture.rs:63
3: 0x55f9aad71196 - panic_hook::panic_hook::h453cc3bee81c2482
at util/panic_hook/src/lib.rs:53
4: 0x55f9aad718f7 - core::ops::function::Fn::call::hc90cace879384a77
at /checkout/src/libcore/ops/function.rs:73
5: 0x55f9ac673e93 - std::panicking::rust_panic_with_hook::he4c3a67f6258a8f9
at libstd/panicking.rs:515
6: 0x55f9ac673be9 - std::panicking::continue_panic_fmt::h156c04b2aea348c7
at libstd/panicking.rs:426
7: 0x55f9ac673905 - rust_begin_unwind
at libstd/panicking.rs:337
8: 0x55f9ac6d482b - core::panicking::panic_fmt::h0e6d5c6fb2a34dd6
at libcore/panicking.rs:92
9: 0x55f9ac6c6f91 - core::option::expect_failed::h388c78b66d038dc6
at libcore/option.rs:960
10: 0x55f9ab139fd5 - <core::option::Option<T>>::expect::hddea359300321f8f
at /checkout/src/libcore/option.rs:312
11: 0x55f9ab1691a0 - codechain_core::client::client::Importer::import_verified_headers::hd5ffb6960429ef0b
at core/src/client/client.rs:874
12: 0x55f9ab15d6ae - codechain_core::client::client::Client::import_verified_headers::h698ba1077f7f8202
at core/src/client/client.rs:158
13: 0x55f9aaf59d11 - <codechain_core::service::ClientIoHandler as codechain_io::IoHandler<codechain_core::service::ClientIoMessage>>::message::h3d43c8530122f621
at core/src/service.rs:100
14: 0x55f9aaf962d1 - codechain_io::worker::Worker::do_work::had39cc149fa9f19f
at /data/sgkim126/workspace/kodebox/codechain/util/io/src/worker.rs:142
15: 0x55f9aaf97028 - codechain_io::worker::Worker::work_loop::h98d3c5be098a8809
at /data/sgkim126/workspace/kodebox/codechain/util/io/src/worker.rs:110
16: 0x55f9aaf94ac0 - codechain_io::worker::Worker::new::{{closure}}::h9947ce4b18082800
at /data/sgkim126/workspace/kodebox/codechain/util/io/src/worker.rs:84
17: 0x55f9ab2d14f3 - std::sys_common::backtrace::__rust_begin_short_backtrace::hfa40317b22fd95f3
at /checkout/src/libstd/sys_common/backtrace.rs:136
18: 0x55f9ab296211 - std::thread::Builder::spawn::{{closure}}::{{closure}}::h3a5270d2609cd2c3
at /checkout/src/libstd/thread/mod.rs:409
19: 0x55f9ab2ba921 - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::ha71c29c10fe2ba62
at /checkout/src/libstd/panic.rs:308
20: 0x55f9ab2d69e6 - std::panicking::try::do_call::he13a22d8989a0778
at /checkout/src/libstd/panicking.rs:310
21: 0x55f9ac69ba59 - __rust_maybe_catch_panic
at libpanic_unwind/lib.rs:105
22: 0x55f9ab2d648e - std::panicking::try::h77e52441914e067e
at /checkout/src/libstd/panicking.rs:289
23: 0x55f9ab2baa63 - std::panic::catch_unwind::h7c9782343fe1e595
at /checkout/src/libstd/panic.rs:392
24: 0x55f9ab295567 - std::thread::Builder::spawn::{{closure}}::h0fee43e61cf8b1be
at /checkout/src/libstd/thread/mod.rs:408
25: 0x55f9ab2964ca - <F as alloc::boxed::FnBox<A>>::call_box::h977333e0ba95649e
at /checkout/src/liballoc/boxed.rs:640
26: 0x55f9ac670d9a - <alloc::boxed::Box<alloc::boxed::FnBox<A, Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$::call_once::h75e539106a648d39
at /checkout/src/liballoc/boxed.rs:650
- std::sys_common::thread::start_thread::h88a639c99862a9f5
at libstd/sys_common/thread.rs:24
27: 0x55f9ac674945 - std::sys::unix::thread::Thread::new::thread_start::h7d7a420a78cfa84d
at libstd/sys/unix/thread.rs:90
28: 0x7f90655306da - start_thread
29: 0x7f906504188e - __clone
30: 0x0 - <unknown>
Thread 'IO Worker CodeChain-io/codechain#3' panicked at 'Parent of importing header must exist', libcore/option.rs:960
This is a bug. Please report it at:
https://github.com/CodeChain-io/codechain/issues/new
Anyone can save any data in CodeChain using the Store transaction. They can also remove it by using the Remove transaction.
In Foundry, that can be done using the module system. Let's remove them.
Currently, stake module implements the encoding/decoding for the map.
https://github.com/CodeChain-io/codechain/blob/5baa5768d381589ddfc450d774900dcf48cf2bb8/core/src/consensus/stake/action_data.rs#L227
IMO, it's better to move it to the rlp module.
I think the function renaming is enough for the purpose.
Snapshot synchronization was originally almost implemented in CodeChain/snapshot
branch.
The blocking problems were related to asset timelocks, and since we're stripping asset implementation in this repository, we just have to port the commits to this repository.
The following is the list of commits to be ported:
It would be nice if we could browse the DB or visualize a portion of it without starting a node.
We don't need it anymore.
The light clients should be able to verify headers with minimum information.
I suggest adding the current validator set hash and the next validator set hash in Header.
The code below is similar to the Tendermint Go implementation's method.
struct Header {
// ...
validator_set_hash: H256,
next_validator_set_hash: H256,
}
struct ValidatorSet {
validators: Vec<Validator>,
proposer: Validator,
total_voting_power: u64,
}
struct Validator {
public_key: Public,
voting_power: i64,
}
CodeChain requests the same prevote or precommit message to all its peers. We don't need to request a vote to all the peers. We can request a vote to a node and make a request to another node only if the first peer does not respond.
CodeChain invalidates transactions whose fee is less than the minimum fee. The fee is charged for the network usage. We should set the minimum fee according to the transaction's CPU cost and Disk cost.
CodeChain requires a fixed fee for a Transfer transaction. A transfer transaction has multiple inputs and outputs. The transaction issuer should pay more fees if the size of the transaction is bigger.
I have one concern. There are two ways to apply the minimum fee: one is the consensus' minimum fee. CodeChain nodes will drop the transactions that have less than the consensus' minimum fee. The other one is each node's minimum fee. Each node can reject to propagate or to mine transactions that have small fees.
IMO, we should implement fee-per-byte minimum fees in both places.
jsonrpc_http_server spits out the following error sometimes:
http.worker00 jsonrpc_http_server Error serving connection: Error { kind: Parse(Header) }
https://github.com/hyperium/hyper/blob/0867ad5c15fa52b7af3fc840ee7a1e256c469942/src/proto/h1/role.rs
There are several situations where Parse::Header
is raised in hyper
. We need to lower the error level of hyper to hyper=debug
to investigate why they are failing.
The current logger neither buffers outputs nor caches atty::is
result. It hurts performance.
See #63
https://github.com/CodeChain-io/codechain/blob/18e1e80af4503cfd4d06e9514e9f88370995abda/sync/src/snapshot/service.rs#L72
Currently, the snapshot service spawns a thread to use the db but doesn't wait for the end of the child thread when it exit. It can corrupt the db.
Currently, a header has 30 signatures. It's almost 2KB.
If we use signature aggregation for seal field, we can reduce the header size sharply.
Make it easy to interact with CodeChain.
A CodeChain node downloads child blocks of an invalid block. Since the parent block is invalid, verifying the child blocks always fails.
Remove timelock related features from the mempool.
CodeChain propagates Prevote and Precommit messages using the following method: Node A tells Node B that it has vote 1, vote 2, and vote 3. Since node B has vote 1, node B ask node A to give vote 2 and vote 3.
Since CodeChain is not recording the vote requests, it can send the same requests to the same peer. If CodeChain can remember the old request, it will not send the same request again and as a result, we can reduce network usage.
We can easily find following pattern in our codebase.
#[cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))]
pub fn new(...) -> Arc<Self>
I think we can adopt following pattern from rust std libraries.
https://doc.rust-lang.org/src/std/io/stdio.rs.html#145-147
https://doc.rust-lang.org/src/std/thread/mod.rs.html#1018-1020
And also, abusing Weak
a little bit, we can make Self as Arc-aware.
struct Outer {
inner: Arc<Inner>
}
struct Inner {
_ref: Weak<Inner>
}
impl Outer {
fn new() -> Outer {
let mut inner = Arc::new(Inner{ _ref: Weak::new() });
inner._ref = inner;
inner
}
}
impl Inner {
fn register_to_something(&self, ext: &Extension) {
ext.register(self._ref.upgrade().unwrap());
}
}
_self: Weak<Self>
, we can
I found that block.state.commit
function is slow.
In Corgi network, when a block has a transaction that splits one UTXO to 100 UTXOs, the block.state.commit
function takes 7 seconds when called by a proposer, takes 5 seconds when is called by other validators.
I added logs to find the function. You can see the logs in this link
Here are the sample logs.
// in proposer
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 TRACE miner Adding transaction 0x7a2813b09fc75f31e94f10af6f8e80d4fdf9e7ab3a856852a5c76a75b5b62018 took 13.64375ms
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Pushed 1/1 transactions
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Get parent hash
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Get parent header
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Get parent view
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Get transactions root
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Clone block state
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Call on_close_block
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 TRACE state add_balance(0x6850…65e1, 50): 2639520825
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 TRACE state add_balance(0x6202…8750, 19): 1300650642
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 TRACE state add_balance(0x263b…fcb1, 30): 1762899421
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 TRACE state add_balance(0x0968…b3f6, 1): 919023814
#105317671 2019-07-25 10:51:27 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner commit state
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Set transactions root
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner set state root
#105317671 2019-07-25 10:51:34 UTC event.loop INFO rpc RPC call(slog([]))
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Close block
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner Before get write access of mem_pool
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 DEBUG miner After get write access of mem_pool
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 TRACE mem_pool remove() called, time: 2126657, timestamp: 1564051884
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 TRACE miner update_sealing: engine indicates internal sealing
#105317671 2019-07-25 10:51:34 UTC Client Worker CodeChain-io/codechain#2 TRACE miner seal_block_internally: attempting internal seal.
#105317671 2019-07-25 10:51:34 UTC tendermint TRACE engine Proposer nonce: 26
// in another validator
#608329186 2019-07-25 11:17:25 UTC Blocks Verifier CodeChain-io/codechain#1 DEBUG miner Before lock block 2126978
#608329186 2019-07-25 11:17:30 UTC Blocks Verifier CodeChain-io/codechain#1 DEBUG miner After lock block 2126978
Currently, the network uses util/io.
It returns a token on an event, instead of the related stream. So the network module should manage the relationship between the token and the stream.
If the network module uses tokio, this complexity can be removed.
The indexer is re-calculating what a node has calculated. The reward calculation of the dynamic validator is also calculated in the indexer, which is very complicated. If CodeChain provides the Trace API, which tells what values in the state are changed for each block, it will help greatly when creating an application
struct StructWithSingleField<T> {
field: T
}
impl<T: Encodable> Encodable for StructWithSingleField<T> {
fn rlp_append(&self, s: &mut RlpStream) {
self.field.rlp_append(s);
}
}
can be simplified to
#[derive(RlpEncodableWrapper)]
struct StructWithSingleField<T> {
field: T
}
It can be applied to struct StructWithSingleTuple<T>(T)
, and RlpDecodable
too.
Our Tendermint implementation locks on a block if 2/3 of prevotes are collected even though the block is not received yet. Changing the behavior should not affect safety. If more than 2/3 of peers are byzantine(very rare case) the node should not send a precommit on the block.
CodeChain saves the version of tendermint backup data. If the backup data's version is later than the code's version, CodeChain should stop and should not remove the backup data.
In Bitcoin, creating a valid header is difficult because of the header's hash should satisfy a special rule. They use the header chain to verify the chain before receiving whole blocks.
CodeChain also has a header chain. CodeChain's header contains signatures from validators. Verifying the header is impossible because the validator set change is not described in the header. The lack of verification allows DoS attacks on the header sync.
We should remove the header chain or make the header chain verifiable. We may add validator set changes in the header to make it verifiable.
In the documentation the EngineError::BadSealFieldSize
is stated as "Seal field has an unexpected size". However, the method check_enough_votes
returns an error of this type when the collected votes do not exceed the threshold.
https://github.com/CodeChain-io/codechain/blob/d91b73a0fe81a8a1431e704d9ef73276ef43ef59/util/rlp/src/stream.rs#L397-L409 this tests the behavior.
Make the above test pass.
We have a tool "auto-self-nominate" written in TypeScript.
We should run "auto-self-nominate" in a separate process from the CodeChain node. Since managing several processes costs a lot, running the same logic in the CodeChain process will reduce the overall managing cost.
Currently, the storage of transaction and transaction result is not organized well.
The current implementation uses five columns to store data. Two of them are used to store a state trie and a mempool backup. You don't need to change these columns. Other columns are used to store headers, bodies, and extra information. I think they can be optimized.
Below describes the current implementation for those columns.
BlockHeader
field name | type |
---|---|
parent_hash | H256 |
author | Address |
state_root | H256 |
transactions_root | H256 |
results_root | H256 |
score | U256 |
number | u64 |
timestamp | u64 |
extra_data | Bytes |
seals | ...Bytes[] |
BlockBody
field name | type | description |
---|---|---|
header | Bytes | rlp of header |
transactions | UnverifiedTransaction[] |
BlockDetails
TransactionAddress
TransactionAddress[]
Invoice[]
[0x1] or [0x2, error_hint]
field name | type |
---|---|
block hash | H256 |
index | usize |
field name | type |
---|---|
number | u64 |
total score | U256 |
parent | H256 |
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.