Skip to content
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

Kaspad with mining support #86

Merged
merged 66 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
514d8cd
Make addresses::Address serializable
tiram88 Nov 24, 2022
b1ac6da
Remove unneeded second protobuf file in build
tiram88 Nov 24, 2022
fc89616
Impl from &Address for String and impl Error for AddressError
tiram88 Nov 26, 2022
5820616
Extend RpcApi with SubmitBlock & GetBlockTemplate
tiram88 Nov 26, 2022
5186c5a
Add ConsensusApi
tiram88 Nov 28, 2022
d4f8c11
Change GetBlockTemplateRequest extra_data type to Vec<u8>
tiram88 Nov 28, 2022
4c99246
Implement a rpc-core get_block_template handler
tiram88 Nov 28, 2022
6c7e0b6
Add todos for RpcBlockHeader
tiram88 Nov 28, 2022
30d184b
Turn gRPC server into a kaspa_core service
tiram88 Nov 29, 2022
8a242b4
Add AsyncRuntime that runs the grpc server
tiram88 Nov 30, 2022
52a59c7
Merge branch 'kaspanet:master' into rpc-mining-ext
tiram88 Nov 30, 2022
43c6256
Limit the AsyncRuntime to 2 worker threads
tiram88 Nov 30, 2022
ae77e92
Clean the protowire builder
tiram88 Dec 1, 2022
b22df50
Update Extending RpcApi instructions
tiram88 Dec 1, 2022
0ad62f4
Some minor adjustments in GrpcServer
tiram88 Dec 1, 2022
b5c6080
Add consensus-core <-> rpc-core tx converters, make verbose data opti…
tiram88 Dec 1, 2022
80b2230
Make addresses::Address serializable
tiram88 Nov 24, 2022
a558728
Remove unneeded second protobuf file in build
tiram88 Nov 24, 2022
3972fed
Impl from &Address for String and impl Error for AddressError
tiram88 Nov 26, 2022
34faa72
Extend RpcApi with SubmitBlock & GetBlockTemplate
tiram88 Nov 26, 2022
5d6a91f
Add ConsensusApi
tiram88 Nov 28, 2022
1d38851
Change GetBlockTemplateRequest extra_data type to Vec<u8>
tiram88 Nov 28, 2022
7e54116
Implement a rpc-core get_block_template handler
tiram88 Nov 28, 2022
defedd1
Add todos for RpcBlockHeader
tiram88 Nov 28, 2022
0953d39
Turn gRPC server into a kaspa_core service
tiram88 Nov 29, 2022
44c0f57
Add AsyncRuntime that runs the grpc server
tiram88 Nov 30, 2022
187667e
Limit the AsyncRuntime to 2 worker threads
tiram88 Nov 30, 2022
eea3d35
Clean the protowire builder
tiram88 Dec 1, 2022
3ed0d96
Update Extending RpcApi instructions
tiram88 Dec 1, 2022
ce2061f
Some minor adjustments in GrpcServer
tiram88 Dec 1, 2022
4b5dc48
Add consensus-core <-> rpc-core tx converters, make verbose data opti…
tiram88 Dec 1, 2022
7dbeee6
Merge branch 'rpc-mining-ext' of https://github.com/tiram88/rusty-kas…
tiram88 Dec 1, 2022
255b74d
Implement ConsensusApi for Consensus and TestConsensus & remove stubs
tiram88 Dec 1, 2022
00d7fc9
cargo update
tiram88 Dec 1, 2022
5bd4e2c
Add a consensus and a gRPC server to kaspad, remove the block emitter
tiram88 Dec 1, 2022
881177b
Fix reopening an existing DB
tiram88 Dec 2, 2022
baa7ed9
Add NewBlockTemplate notification
tiram88 Dec 2, 2022
b480f91
Refactor AsyncRuntime & add RpcCoreServer
tiram88 Dec 3, 2022
73c9f8d
Rely on AsyncRuntime to spawn tokio tasks
tiram88 Dec 3, 2022
d505826
Add validate_and_insert_block to ConsensusApi
tiram88 Dec 3, 2022
c89acf8
Implement a rpc-core submit_block handler
tiram88 Dec 3, 2022
f4ea63e
Raise a NewBlockTemplateNotification when validate_and_insert_block h…
tiram88 Dec 4, 2022
b43a6ec
Merge branch 'master' into rpc-mining-ext
tiram88 Dec 4, 2022
ef9ba05
Apply Michael's patch
tiram88 Dec 4, 2022
351a352
Add transactions to RpcBlock to Block converter
tiram88 Dec 4, 2022
4b27ea6
Temporarily disable NewBlockTemplate notifications
tiram88 Dec 4, 2022
8e58978
Disable monitoring and change default port to reflect devnet defaults
tiram88 Dec 4, 2022
2c37b7c
Convert tx inputs and outputs from rpc-core to consensus-core
tiram88 Dec 4, 2022
1be9a4d
Some tracing commands
tiram88 Dec 4, 2022
83e8c99
Change devnet genesis bits,, lower tracing verbosity, re-enable NewBl…
tiram88 Dec 4, 2022
7050a9e
Apply real genesis bits observed on testnet to devnet params
tiram88 Dec 4, 2022
4809eeb
Adapting some more traces
tiram88 Dec 4, 2022
210cc26
Move BlockStatus to consensus-core and use it in ConsensusApi validat…
tiram88 Dec 5, 2022
26d1bb8
Rename rpc-core RpcBlockHeader to RpcHeader and make it binary closer…
tiram88 Dec 5, 2022
7c1c164
Add a basic logger
tiram88 Dec 6, 2022
bf6a610
Fix ConsensusMonitor and its usage in Consensus
tiram88 Dec 6, 2022
cd4588e
Fix typo
tiram88 Dec 6, 2022
022b061
Cleaning some minor details
tiram88 Dec 6, 2022
2e45c17
Change monitor log interval to 10 seconds + fix typos
michaelsutton Dec 6, 2022
87704f8
Fix spelling errors
tiram88 Dec 6, 2022
f366184
Apply review requests
tiram88 Dec 7, 2022
03998f8
Update readme (for kaspad)
tiram88 Dec 7, 2022
3a461f9
Update readme (adding simpa plus some edits)
michaelsutton Dec 7, 2022
619e797
Merge branch 'master' into rpc-mining-ext
michaelsutton Dec 7, 2022
a48a3cc
Restructure readme sectoins and add a warning to simpa
michaelsutton Dec 7, 2022
75f593c
Correct typo
tiram88 Dec 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 131 additions & 68 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ borsh = "0.9.3"
clap = { version = "4.0.23", features = ["derive"] }
async-std = { version = "1.12.0", features = ['attributes'] }
derive_more = { version = "0.99" }
log = "0.4"
47 changes: 43 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,60 @@
# Kaspa on Rust


Work in progress to implement the Kaspa full-node and related libraries in the Rust programming language.

## Getting started

- Install the [rust toolchain](https://rustup.rs/).

- Run the following commands:

```bash
$ git clone https://github.com/kaspanet/rusty-kaspa
$ cd rusty-kaspa/kaspad
$ cargo run --release
$ cd rusty-kaspa
```

## Experimenting with the node

The `kaspad` rust executable is currently at the initial stage where a devnet consensus instance can be built and mined locally through the RPC interface. The P2P network is not supported yet. To see it in action, perform the following:

```bash
$ cargo run --bin kaspad --release
```

- Download and unzip the latest binaries bundle of [kaspanet/kaspad](https://github.com/kaspanet/kaspad/releases).

- In a separate terminal run the kaspanet/kaspad miner:

```bash
$ kaspaminer --rpcserver 127.0.0.1:16610 --devnet --miningaddr kaspadev:qrcqat6l9zcjsu7swnaztqzrv0s7hu04skpaezxk43y4etj8ncwfkuhy0zmax
```

- This will run a short simulation producing a random DAG and processing it (applying all currently implemented logic).
- This will create and feed a DAG with the miner getting block templates from the node and submitting them back when mined. The node processes and stores the blocks while applying all currently implemented logic. Execution can be stopped and resumed, the data is persisted in a database.

## Simulation framework (Simpa)

Additionally, the current codebase supports a full in-process network simulation, building an actual DAG over virtual time with virtual delay and benchmarking validation time (following the simulation generation). Execute
```bash
cargo run --release --bin simpa -- --help
```
to see the full command line configuration supported by `simpa`. For instance, the following command will run a simulation producing 1000 blocks with communication delay of 2 seconds and BPS=8, and attempts to fill each block with up to 200 transactions.

```bash
$ cargo run --release --bin simpa -- -t=200 -d=2 -b=8 -n=1000
```

## Logging

Logging in `kaspad` and `simpa` can be [filtered](https://docs.rs/env_logger/0.10.0/env_logger/#filtering-results) either by defining the environment variable `RUST_LOG` and/or by adding a `--loglevel` argument to the command, ie.:

```bash
$ cargo run --bin kaspad -- --loglevel info,rpc_core=trace,rpc_grpc=trace,consensus=trace,kaspa_core=trace
```

## Tests & Benchmarks

- To run all current tests use:

```bash
$ cd rusty-kaspa
$ cargo test --release
Expand All @@ -25,6 +63,7 @@ $ cargo nextest run --release
```

- To run current benchmarks:

```bash
$ cd rusty-kaspa
$ cargo bench
Expand Down
1 change: 1 addition & 0 deletions consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rand.workspace = true
indexmap.workspace = true
smallvec.workspace = true
kaspa-utils.workspace = true
log.workspace = true

rocksdb = "0.19"
parking_lot = "0.12"
Expand Down
3 changes: 2 additions & 1 deletion consensus/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ serde.workspace = true
faster-hex.workspace = true
smallvec.workspace = true
borsh.workspace = true
secp256k1 = { version = "0.24", features = ["global-context", "rand-std"] }
secp256k1 = { version = "0.24", features = ["global-context", "rand-std"] }
futures-util.workspace = true
22 changes: 22 additions & 0 deletions consensus/core/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use futures_util::future::BoxFuture;
use std::sync::Arc;

use crate::{
block::{Block, BlockTemplate},
blockstatus::BlockStatus,
coinbase::MinerData,
tx::Transaction,
};

/// Abstracts the consensus external API
pub trait ConsensusApi: Send + Sync {
fn build_block_template(self: Arc<Self>, miner_data: MinerData, txs: Vec<Transaction>) -> BlockTemplate;

fn validate_and_insert_block(
self: Arc<Self>,
block: Block,
update_virtual: bool,
) -> BoxFuture<'static, Result<BlockStatus, String>>;
}

pub type DynConsensus = Arc<dyn ConsensusApi>;
31 changes: 31 additions & 0 deletions consensus/core/src/blockstatus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use serde::{Deserialize, Serialize};

#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Debug)]
pub enum BlockStatus {
/// StatusInvalid indicates that the block is invalid.
StatusInvalid,

/// StatusUTXOValid indicates the block is valid from any UTXO related aspects and has passed all the other validations as well.
StatusUTXOValid,

/// StatusUTXOPendingVerification indicates that the block is pending verification against its past UTXO-Set, either
/// because it was not yet verified since the block was never in the selected parent chain, or if the
/// block violates finality.
StatusUTXOPendingVerification,

/// StatusDisqualifiedFromChain indicates that the block is not eligible to be a selected parent.
StatusDisqualifiedFromChain,

/// StatusHeaderOnly indicates that the block transactions are not held (pruned or wasn't added yet)
StatusHeaderOnly,
}

impl BlockStatus {
pub fn has_block_body(self) -> bool {
matches!(self, Self::StatusUTXOValid | Self::StatusUTXOPendingVerification | Self::StatusDisqualifiedFromChain)
}

pub fn is_utxo_valid_or_pending(self) -> bool {
matches!(self, Self::StatusUTXOValid | Self::StatusUTXOPendingVerification)
}
}
2 changes: 2 additions & 0 deletions consensus/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use std::hash::{BuildHasher, Hasher};

use hashes::Hash;

pub mod api;
pub mod block;
pub mod blockhash;
pub mod blockstatus;
pub mod coinbase;
pub mod hashing;
pub mod header;
Expand Down
4 changes: 4 additions & 0 deletions consensus/core/src/notify/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ use crate::block::Block;
#[derive(Debug, Clone)]
pub enum Notification {
BlockAdded(BlockAddedNotification),
NewBlockTemplate(NewBlockTemplateNotification),
}

#[derive(Debug, Clone)]
pub struct BlockAddedNotification {
pub block: Block,
}

#[derive(Debug, Clone)]
pub struct NewBlockTemplateNotification {}
4 changes: 3 additions & 1 deletion consensus/core/src/tx.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use std::fmt::Display;
Expand Down Expand Up @@ -62,7 +63,8 @@ impl UtxoEntry {
pub type TransactionIndexType = u32;

/// Represents a Kaspa transaction outpoint
#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone, Serialize, Deserialize)]
#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize, BorshSchema)]
#[serde(rename_all = "camelCase")]
pub struct TransactionOutpoint {
pub transaction_id: TransactionId,
pub index: TransactionIndexType,
Expand Down
29 changes: 26 additions & 3 deletions consensus/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
pruning::DbPruningStore,
reachability::DbReachabilityStore,
relations::DbRelationsStore,
statuses::{BlockStatus, DbStatusesStore, StatusesStoreReader},
statuses::{DbStatusesStore, StatusesStoreReader},
tips::{DbTipsStore, TipsStoreReader},
utxo_diffs::DbUtxoDiffsStore,
utxo_multisets::DbUtxoMultisetsStore,
Expand All @@ -45,16 +45,19 @@ use crate::{
},
};
use consensus_core::{
api::ConsensusApi,
block::{Block, BlockTemplate},
blockstatus::BlockStatus,
coinbase::MinerData,
tx::Transaction,
BlockHashSet,
};
use crossbeam_channel::{unbounded, Receiver, Sender};
use futures_util::future::BoxFuture;
use hashes::Hash;
use kaspa_core::{core::Core, service::Service};
use parking_lot::RwLock;
use std::future::Future;
use std::{future::Future, sync::atomic::Ordering};
use std::{
ops::DerefMut,
sync::Arc,
Expand Down Expand Up @@ -392,10 +395,11 @@ impl Consensus {
pub fn validate_and_insert_block(&self, block: Block) -> impl Future<Output = BlockProcessResult<BlockStatus>> {
let (tx, rx): (BlockResultSender, _) = oneshot::channel();
self.block_sender.send(BlockTask::Process(block, vec![tx])).unwrap();
self.counters.blocks_submitted.fetch_add(1, Ordering::SeqCst);
async { rx.await.unwrap() }
}

pub fn build_block_template(self: &Arc<Self>, miner_data: MinerData, txs: Vec<Transaction>) -> BlockTemplate {
pub fn build_block_template(&self, miner_data: MinerData, txs: Vec<Transaction>) -> BlockTemplate {
self.virtual_processor.build_block_template(miner_data, txs)
}

Expand All @@ -407,6 +411,10 @@ impl Consensus {
self.statuses_store.read().get(hash).unwrap()
}

pub fn processing_counters(&self) -> &Arc<ProcessingCounters> {
&self.counters
}

pub fn signal_exit(&self) {
self.block_sender.send(BlockTask::Exit).unwrap();
}
Expand All @@ -420,6 +428,21 @@ impl Consensus {
}
}

impl ConsensusApi for Consensus {
fn build_block_template(self: Arc<Self>, miner_data: MinerData, txs: Vec<Transaction>) -> BlockTemplate {
self.as_ref().build_block_template(miner_data, txs)
}

fn validate_and_insert_block(
self: Arc<Self>,
block: Block,
_update_virtual: bool,
) -> BoxFuture<'static, Result<BlockStatus, String>> {
let result = self.as_ref().validate_and_insert_block(block);
Box::pin(async move { result.await.map_err(|err| err.to_string()) })
}
}

impl Service for Consensus {
fn ident(self: Arc<Consensus>) -> &'static str {
"consensus"
Expand Down
29 changes: 23 additions & 6 deletions consensus/src/consensus/test_consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ use std::{
};

use consensus_core::{
block::{Block, MutableBlock},
api::ConsensusApi,
block::{Block, BlockTemplate, MutableBlock},
blockstatus::BlockStatus,
coinbase::MinerData,
header::Header,
merkle::calc_hash_merkle_root,
subnets::SUBNETWORK_ID_COINBASE,
tx::Transaction,
BlockHashSet,
};
use futures_util::future::BoxFuture;
use hashes::Hash;
use kaspa_core::{core::Core, service::Service};
use parking_lot::RwLock;
Expand All @@ -26,7 +30,6 @@ use crate::{
headers::{DbHeadersStore, HeaderStoreReader},
pruning::PruningStoreReader,
reachability::DbReachabilityStore,
statuses::BlockStatus,
DB,
},
params::Params,
Expand All @@ -38,19 +41,19 @@ use crate::{
use super::{Consensus, DbGhostdagManager};

pub struct TestConsensus {
consensus: Consensus,
consensus: Arc<Consensus>,
pub params: Params,
temp_db_lifetime: TempDbLifetime,
}

impl TestConsensus {
pub fn new(db: Arc<DB>, params: &Params) -> Self {
Self { consensus: Consensus::new(db, params), params: params.clone(), temp_db_lifetime: Default::default() }
Self { consensus: Arc::new(Consensus::new(db, params)), params: params.clone(), temp_db_lifetime: Default::default() }
}

pub fn create_from_temp_db(params: &Params) -> Self {
let (temp_db_lifetime, db) = create_temp_db();
Self { consensus: Consensus::new(db, params), params: params.clone(), temp_db_lifetime }
Self { consensus: Arc::new(Consensus::new(db, params)), params: params.clone(), temp_db_lifetime }
}

pub fn build_header_with_parents(&self, hash: Hash, parents: Vec<Hash>) -> Header {
Expand Down Expand Up @@ -102,7 +105,7 @@ impl TestConsensus {
}

pub fn validate_and_insert_block(&self, block: Block) -> impl Future<Output = BlockProcessResult<BlockStatus>> {
self.consensus.validate_and_insert_block(block)
self.consensus.as_ref().validate_and_insert_block(block)
}

pub fn init(&self) -> Vec<JoinHandle<()>> {
Expand Down Expand Up @@ -154,6 +157,20 @@ impl TestConsensus {
}
}

impl ConsensusApi for TestConsensus {
fn build_block_template(self: Arc<Self>, miner_data: MinerData, txs: Vec<Transaction>) -> BlockTemplate {
self.consensus.clone().build_block_template(miner_data, txs)
}

fn validate_and_insert_block(
self: Arc<Self>,
block: Block,
update_virtual: bool,
) -> BoxFuture<'static, Result<BlockStatus, String>> {
self.consensus.clone().validate_and_insert_block(block, update_virtual)
}
}

impl Service for TestConsensus {
fn ident(self: Arc<TestConsensus>) -> &'static str {
"test-consensus"
Expand Down
3 changes: 2 additions & 1 deletion consensus/src/model/services/statuses.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::model::stores::statuses::{BlockStatus, StatusesStoreReader};
use crate::model::stores::statuses::StatusesStoreReader;
use consensus_core::blockstatus::BlockStatus;
use hashes::Hash;
use parking_lot::RwLock;
use std::sync::Arc;
Expand Down
33 changes: 1 addition & 32 deletions consensus/src/model/stores/statuses.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use consensus_core::BlockHasher;
use consensus_core::{blockstatus::BlockStatus, BlockHasher};
use parking_lot::{RwLock, RwLockWriteGuard};
use rocksdb::WriteBatch;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

use super::{
Expand All @@ -11,36 +10,6 @@ use super::{
};
use hashes::Hash;

#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Debug)]
pub enum BlockStatus {
/// StatusInvalid indicates that the block is invalid.
StatusInvalid,

/// StatusUTXOValid indicates the block is valid from any UTXO related aspects and has passed all the other validations as well.
StatusUTXOValid,

/// StatusUTXOPendingVerification indicates that the block is pending verification against its past UTXO-Set, either
/// because it was not yet verified since the block was never in the selected parent chain, or if the
/// block violates finality.
StatusUTXOPendingVerification,

/// StatusDisqualifiedFromChain indicates that the block is not eligible to be a selected parent.
StatusDisqualifiedFromChain,

/// StatusHeaderOnly indicates that the block transactions are not held (pruned or wasn't added yet)
StatusHeaderOnly,
}

impl BlockStatus {
pub fn has_block_body(self) -> bool {
matches!(self, Self::StatusUTXOValid | Self::StatusUTXOPendingVerification | Self::StatusDisqualifiedFromChain)
}

pub fn is_utxo_valid_or_pending(self) -> bool {
matches!(self, Self::StatusUTXOValid | Self::StatusUTXOPendingVerification)
}
}

/// Reader API for `StatusesStore`.
pub trait StatusesStoreReader {
fn get(&self, hash: Hash) -> StoreResult<BlockStatus>;
Expand Down
Loading