add tari-gbt(rust)

This commit is contained in:
lzx 2025-09-04 16:09:36 +08:00
parent 953a76439a
commit 8cc56a489e
65 changed files with 4851 additions and 14397 deletions

View File

@ -1,4 +1,4 @@
# tari-server
# m2pool-mining-core
一个基于 Go 的轻量化挖矿池服务内核,包含 Job 生成/分发与 Stratum 矿工端接入两大模块:
- gbt区块模板生成与同步GetBlockTemplate/Job Producer通过 ZMQ 向服务端发布新任务

3
go.mod
View File

@ -6,16 +6,15 @@ toolchain go1.23.1
require (
github.com/btcsuite/btcd v0.24.2
github.com/golang/protobuf v1.5.4
github.com/zeromq/goczmq v4.1.0+incompatible
go.uber.org/zap v1.27.0
google.golang.org/protobuf v1.36.6
)
require (
golang.org/x/net v0.41.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)
require (

View File

@ -12,9 +12,8 @@ import (
//"pool/internal/cache"
"pool/internal/gbt/coin"
"pool/internal/gbt/monero"
monero_rpc "pool/internal/gbt/monero/rpc"
"pool/internal/gbt/tari"
"pool/internal/gbt/tari/sha3x"
"pool/internal/utility"
"os"
@ -49,15 +48,6 @@ func InitClient(gbt *coin.GbtContext) error {
rpcClient := monero_rpc.NewHttpClient(url, 10*time.Second)
gbt.MoneroClinet = rpcClient
gbt.MoneroAddr = gbt.Config.Rpc.User
case "sha3x":
url := gbt.Config.Rpc.Host
grpcClient, err := tari.NewBaseNodeClient(url)
if err != nil {
fmt.Println("tari创建grpc服务失败", err)
return err
}
gbt.TariClient = grpcClient
gbt.TariAddr = gbt.Config.Rpc.Host
default:
var config rpcclient.ConnConfig
if gbt.Config.Rpc.Type == "testnet" {
@ -145,8 +135,8 @@ type coinobj struct {
var coinobjs = []coinobj{
// {Coin: "nexa", Init: nexa.Init, Start: nexa.Start, Stop: nexa.Stop},
// {Coin: "monero", Init: monero.Init, Start: monero.Start, Stop: monero.Stop},
{Coin: "sha3x", Init: sha3x.Init, Start: sha3x.Start, Stop: sha3x.Stop},
{Coin: "monero", Init: monero.Init, Start: monero.Start, Stop: monero.Stop},
// {Coin: "sha3x", Init: sha3x.Init, Start: sha3x.Start, Stop: sha3x.Stop},
}
func register_signal(dbctx *db.DbContext) {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
# A sample log configuration file for running in release mode. By default, this configuration splits up log messages to
# three destinations:
# * Console: For log messages with level INFO and higher
# * log/miner/network.log: INFO-level logs related to the comms crate. This file will be quite busy since there
# are lots of P2P debug messages, and so this traffic is segregated from the application log messages
#
# See https://docs.rs/log4rs/0.8.3/log4rs/encode/pattern/index.html for deciphering the log pattern. The log format
# used in this sample configuration prints messages as:
# timestamp [target] LEVEL message
refresh_rate: 30 seconds
appenders:
# An appender named "stdout" that writes to stdout
stdout:
kind: console
encoder:
pattern: "{d(%H:%M)} {h({l}):5} {m}{n}"
filters:
- kind: threshold
level: info
# An appender named "base_layer" that writes to a file with a custom pattern encoder
miner:
kind: rolling_file
path: "{{log_dir}}/log/miner/miner.log"
policy:
kind: compound
trigger:
kind: size
limit: 10mb
roller:
kind: fixed_window
base: 1
count: 5
pattern: "{{log_dir}}/log/miner/miner.{}.log"
encoder:
pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}"
# Set the default logging level to "warn" and attach the "stdout" appender to the root
root:
level: info
appenders:
- stdout
loggers:
# miner
minotari::application:
level: info
appenders:
- miner
- stdout
additive: false
minotari::miner:
level: info
appenders:
- miner
- stdout
additive: false
minotari_miner:
level: info
appenders:
- miner
- stdout
additive: false

View File

@ -0,0 +1,68 @@
[package]
name = "minotari_miner"
authors = ["The Tari Development Community"]
description = "The tari miner implementation"
repository = "https://github.com/tari-project/tari"
license = "BSD-3-Clause"
version = "4.9.0"
edition = "2018"
[dependencies]
tari_core = { path = "../../base_layer/core", default-features = false }
tari_common = { path = "../../common" }
tari_common_types = { path = "../../base_layer/common_types" }
tari_max_size = { path = "../../infrastructure/max_size" }
minotari_app_utilities = { path = "../minotari_app_utilities", features = [
"miner_input",
] }
minotari_app_grpc = { path = "../minotari_app_grpc" }
tari_utilities = { version = "0.8" }
base64 = "0.13.0"
borsh = "1.5.7"
bufstream = "0.1"
chrono = { version = "0.4.39", default-features = false }
clap = { version = "3.2", features = ["derive"] }
crossbeam = "0.8"
crossterm = { version = "0.28" }
derivative = "2.2.0"
futures = "0.3"
hex = "0.4.2"
log = { version = "0.4", features = ["std"] }
log4rs = { version = "1.3.0", default-features = false, features = [
"config_parsing",
"threshold_filter",
"yaml_format",
"console_appender",
"rolling_file_appender",
"compound_policy",
"size_trigger",
"fixed_window_roller",
] }
native-tls = "0.2"
num_cpus = "1.13"
rand = "0.8"
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = "1.0.57"
thiserror = "1.0"
tokio = { version = "1.44", default-features = false, features = [
"rt-multi-thread",
] }
tonic = { version = "0.13.1", features = ["tls-ring", "tls-native-roots"] }
zmq = "0.10"
anyhow = "1.0"
[dev-dependencies]
prost-types = "0.13.3"
chrono = { version = "0.4.39", default-features = false }
config = "0.14.0"
zmq = "0.10"
anyhow = "1.0"
[package.metadata.cargo-machete]
ignored = [
# We need to specify extra features for log4rs even though it is not used directly in this crate
"log4rs",
"prost",
]

View File

@ -0,0 +1,39 @@
# Standalone miner for the Minotari network
The Minotari Miner application should be running connected to the Minotari Base Node and the Minotari Console Wallet,
allowing it insert the coinbase transactions created by the Minotari Wallet and to to mine blocks matching the
required network difficulty. This also serves as a reference implementation for custom miners that which can be derived
from it.
### Installation
Please refer to the relevant section in the main
[README installation section](https://github.com/tari-project/tari/blob/development/README.md#install-and-run).
### Configuration
When running with local versions of the Minotari Base Node and the Minotari Wallet, no additional configuration other
than what is described in the main
[README configuration section](https://github.com/tari-project/tari/blob/development/README.md#tari-sha3-mining)
is required. The Minotari Miner can also be located on a remote workstation.
Configuration options for the Minotari Miner are as follows:
- `base_node_grpc_address` - this is IPv4/IPv6 address including port number, by which the Minotari Base Node can be found;
- `num_mining_threads` - the number of mining threads, which defaults to the number of CPU cores;
- `mine_on_tip_only` - mining will only start when the Minotari Base Node reports it is in the bootstrapped state;
- `proof_of_work_algo` - The proof of work algorithm to use
- `validate_tip_timeout_sec` - the interval at which the current block height will be checked to determine if mining
must be restarted, whereby the tip might have advanced passed the block height that is in use in the current template.
- `mining_pool_address` - Stratum Mode configuration - mining pool address
- `mining_wallet_address` - `Stratum Mode configuration - mining wallet address/public key`
- `mining_worker_name` - `Stratum Mode configuration - mining worker name`
- `coinbase_extra` - Note that this data is publicly readable, but it is suggested you populate it so that pool
dominance can be seen before any one party has more than 51%.
- `network` - "Selected network"
- `wait_timeout_on_error` - "Base node reconnect timeout after any gRPC or miner error"
- `wallet_payment_address` - "The Tari wallet address where the mining funds will be sent to"
### Caveats
Currently, the Minotari Miner only supports SHA3 mining; this is adequate for the current Tari protocol.

View File

@ -0,0 +1,33 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#[cfg(windows)]
fn main() {
use std::env;
println!("cargo:rerun-if-changed=icon.res");
let mut path = env::current_dir().unwrap();
path.push("icon.res");
println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap());
}
#[cfg(not(windows))]
fn main() {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

View File

@ -0,0 +1 @@
miner ICON "icon.ico"

Binary file not shown.

View File

@ -0,0 +1,53 @@
#!/bin/bash
#
# Copyright 2024. The Tari Project
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
echo
echo "Starting Miner"
echo
# Initialize
if [ -z "${use_parent_paths}" ]
then
base_path="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
config_path="${base_path}/config"
exe_path="${base_path}/runtime"
fi
"${exe_path}/start_tor.sh"
if [ ! -f "${config_path}/log4rs_miner.yml" ]
then
echo Creating new "${config_path}/log4rs_miner.yml";
init_flag="--init"
else
echo Using existing "${config_path}/log4rs_miner.yml";
init_flag=""
fi
echo
# Run
echo Spawning Miner into new terminal..
echo
gnome-terminal --working-directory="$PWD" -- "${exe_path}/minotari_miner" ${init_flag} --config "${config_path}/config.toml" --log_config "${config_path}/log4rs_miner.yml" --base-path ${base_path}

View File

@ -0,0 +1 @@
./runtime/start_minotari_miner.sh

View File

@ -0,0 +1,62 @@
# A sample log configuration file for running in release mode. By default, this configuration splits up log messages to
# three destinations:
# * Console: For log messages with level INFO and higher
# * log/miner/network.log: INFO-level logs related to the comms crate. This file will be quite busy since there
# are lots of P2P debug messages, and so this traffic is segregated from the application log messages
#
# See https://docs.rs/log4rs/0.8.3/log4rs/encode/pattern/index.html for deciphering the log pattern. The log format
# used in this sample configuration prints messages as:
# timestamp [target] LEVEL message
refresh_rate: 30 seconds
appenders:
# An appender named "stdout" that writes to stdout
stdout:
kind: console
encoder:
pattern: "{d(%H:%M)} {h({l}):5} {m}{n}"
filters:
- kind: threshold
level: info
# An appender named "base_layer" that writes to a file with a custom pattern encoder
miner:
kind: rolling_file
path: "{{log_dir}}/log/miner/miner.log"
policy:
kind: compound
trigger:
kind: size
limit: 10mb
roller:
kind: fixed_window
base: 1
count: 5
pattern: "{{log_dir}}/log/miner/miner.{}.log"
encoder:
pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}"
# Set the default logging level to "warn" and attach the "stdout" appender to the root
root:
level: warn
appenders:
- stdout
loggers:
# miner
minotari::application:
level: debug
appenders:
- miner
- stdout
additive: false
minotari::miner:
level: debug
appenders:
- miner
- stdout
additive: false
minotari_miner:
level: debug
appenders:
- miner
- stdout
additive: false

View File

@ -0,0 +1,63 @@
#!/bin/bash
#
# Copyright 2024. The Tari Project
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
echo
echo "Starting Miner"
echo
# Initialize
if [ -z "${use_parent_paths}" ]
then
base_path="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
config_path="${base_path}/config"
exe_path="${base_path}/runtime"
fi
tor_running=$(lsof -nP -iTCP:9050)
if [ -z "${tor_running}" ]
then
echo "Starting Tor"
open -a Terminal.app "${exe_path}/start_tor.sh"
ping -c 15 localhost > /dev/null
fi
if [ ! -f "${config_path}/log4rs_miner.yml" ]
then
echo Creating new "${config_path}/log4rs_miner.yml";
init_flag="--init"
else
echo Using existing "${config_path}/log4rs_miner.yml";
init_flag=""
fi
echo
# Run
echo Spawning Console Wallet into new terminal..
echo "${exe_path}/minotari_miner" ${init_flag} --config="${config_path}/config.toml" --log_config="${config_path}/log4rs_miner.yml" --base-path=${base_path} > $exe_path/tari_miner_command.sh
chmod +x $exe_path/minotari_miner_command.sh
open -a terminal $exe_path/minotari_miner_command.sh
echo

View File

@ -0,0 +1 @@
./runtime/start_minotari_miner.sh

View File

@ -0,0 +1,70 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use clap::Parser;
use minotari_app_utilities::common_cli_args::CommonCliArgs;
use tari_common::configuration::{ConfigOverrideProvider, Network};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
pub struct Cli {
#[clap(flatten)]
pub common: CommonCliArgs,
#[clap(long, alias = "mine-until-height")]
pub mine_until_height: Option<u64>,
#[clap(long, alias = "max-blocks")]
pub miner_max_blocks: Option<u64>,
#[clap(long, alias = "min-difficulty")]
pub miner_min_diff: Option<u64>,
#[clap(long, alias = "max-difficulty")]
pub miner_max_diff: Option<u64>,
#[clap(short, long, alias = "non-interactive", env = "TARI_NON_INTERACTIVE")]
pub non_interactive_mode: bool,
#[clap(long, alias = "zmq-pub-port", default_value = "11113")]
zmq_pub_port: u16,
#[clap(long, alias = "zmq-sub-port", default_value = "11112")]
zmq_sub_port: u16,
}
impl ConfigOverrideProvider for Cli {
/// Get the configuration property overrides for the given network. In case of duplicates, the final override
/// added to the list will have preference.
fn get_config_property_overrides(&self, network: &Network) -> Vec<(String, String)> {
// Config file overrides
let mut overrides = vec![("miner.network".to_string(), network.to_string())];
// Command-line overrides
let command_line_overrides = self.common.get_config_property_overrides(network);
command_line_overrides.iter().for_each(|(k, v)| {
replace_or_add_override(&mut overrides, k, v);
});
overrides
}
}
fn replace_or_add_override(overrides: &mut Vec<(String, String)>, key: &str, value: &str) {
if let Some(index) = overrides.iter().position(|(k, _)| k == key) {
overrides.remove(index);
}
overrides.push((key.to_string(), value.to_string()));
}

View File

@ -0,0 +1,184 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Minotari Miner Node derives all
// configuration management
//! from [tari_common] crate, also extending with few
//! specific options:
//! - base_node_grpc_address - is IPv4/IPv6 address including port number, by which Minotari Base Node can be found
//! - num_mining_threads - number of mining threads, defaults to number of cpu cores
//! - mine_on_tip_only - will start mining only when node is reporting bootstrapped state
//! - validate_tip_timeout_sec - will check tip with node every N seconds to validate that still mining on a tip All
//! miner options configured under `[miner]` section of Minotari's `config.toml`.
use std::{
path::{Path, PathBuf},
time::Duration,
};
use minotari_app_grpc::tari_rpc::{pow_algo::PowAlgos, NewBlockTemplateRequest, PowAlgo};
use serde::{Deserialize, Serialize};
use tari_common::{
configuration::{utils::deserialize_string_or_struct, Network},
SubConfigPath,
};
use tari_common_types::{grpc_authentication::GrpcAuthentication, tari_address::TariAddress};
use tari_core::{proof_of_work::PowAlgorithm, transactions::transaction_components::RangeProofType};
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct MinerConfig {
/// gRPC address of base node
pub base_node_grpc_address: Option<String>,
/// GRPC authentication for base node
pub base_node_grpc_authentication: GrpcAuthentication,
/// GRPC domain name for node TLS validation
pub base_node_grpc_tls_domain_name: Option<String>,
/// GRPC ca cert name for TLS
pub base_node_grpc_ca_cert_filename: String,
/// Number of mining threads
pub num_mining_threads: usize,
/// Start mining only when base node is bootstrapped and current block height is on the tip of network
pub mine_on_tip_only: bool,
/// The proof of work algorithm to use (Sha3x or RandomXT)
#[serde(deserialize_with = "deserialize_string_or_struct")]
pub proof_of_work_algo: PowAlgorithm,
/// Will check tip with node every N seconds and restart mining if height already taken and option
/// `mine_on_tip_only` is set to true
pub validate_tip_timeout_sec: u64,
/// Stratum Mode configuration - mining pool address
pub stratum_mining_pool_address: String,
/// Stratum Mode configuration - mining wallet address/public key
pub stratum_mining_wallet_address: String,
/// Stratum Mode configuration - mining worker name
pub mining_worker_name: String,
/// The extra data to store in the coinbase, usually some data about the mining pool.
/// Note that this data is publicly readable, but it is suggested you populate it so that
/// pool dominance can be seen before any one party has more than 51%.
pub coinbase_extra: String,
/// Selected network
pub network: Network,
/// Base node reconnect timeout after any gRPC or miner error
pub wait_timeout_on_error: u64,
/// The relative path to store persistent config
pub config_dir: PathBuf,
/// The Tari wallet address (valid address in hex) where the mining funds will be sent to - must be assigned
pub wallet_payment_address: String,
/// Range proof type - revealed_value or bullet_proof_plus: (default = revealed_value)
pub range_proof_type: RangeProofType,
/// SHA based p2pool decentralized mining enabled or not
pub sha_p2pool_enabled: bool,
pub zmq_publisher_port: u16,
pub zmq_subscriber_port: u16,
}
impl SubConfigPath for MinerConfig {
fn main_key_prefix() -> &'static str {
"miner"
}
}
impl Default for MinerConfig {
fn default() -> Self {
Self {
base_node_grpc_address: None,
base_node_grpc_authentication: GrpcAuthentication::default(),
base_node_grpc_tls_domain_name: None,
base_node_grpc_ca_cert_filename: "node_ca.pem".to_string(),
num_mining_threads: num_cpus::get(),
mine_on_tip_only: true,
proof_of_work_algo: PowAlgorithm::Sha3x,
validate_tip_timeout_sec: 30,
stratum_mining_pool_address: String::new(),
stratum_mining_wallet_address: String::new(),
mining_worker_name: String::new(),
coinbase_extra: "m2pool.com".to_string(),
network: Default::default(),
wait_timeout_on_error: 10,
config_dir: PathBuf::from("config/miner"),
wallet_payment_address: TariAddress::default().to_base58(),
range_proof_type: RangeProofType::RevealedValue,
sha_p2pool_enabled: false,
zmq_publisher_port: 11112,
zmq_subscriber_port: 11113,
}
}
}
impl MinerConfig {
pub fn pow_algo_request(&self) -> NewBlockTemplateRequest {
let algo = match self.proof_of_work_algo {
PowAlgorithm::Sha3x => Some(PowAlgo {
pow_algo: PowAlgos::Sha3x.into(),
}),
PowAlgorithm::RandomXM => Some(PowAlgo {
pow_algo: PowAlgos::Randomxm.into(),
}),
PowAlgorithm::RandomXT => Some(PowAlgo {
pow_algo: PowAlgos::Randomxt.into(),
}),
};
NewBlockTemplateRequest { algo, max_weight: 0 }
}
pub fn wait_timeout(&self) -> Duration {
Duration::from_secs(self.wait_timeout_on_error)
}
pub fn validate_tip_interval(&self) -> Duration {
Duration::from_secs(self.validate_tip_timeout_sec)
}
pub fn set_base_path<P: AsRef<Path>>(&mut self, base_path: P) {
if !self.config_dir.is_absolute() {
self.config_dir = base_path.as_ref().join(self.config_dir.as_path());
}
}
}
#[cfg(test)]
mod test {
use tari_common::DefaultConfigLoader;
use crate::config::MinerConfig;
#[test]
fn miner_configuration() {
const CONFIG: &str = r#"
[miner]
num_mining_threads=2
base_node_grpc_address = "http://my_base_node:1234"
mine_on_tip_only = false
"#;
let mut cfg: config::Config = config::Config::default();
#[allow(deprecated)]
cfg.merge(config::File::from_str(CONFIG, config::FileFormat::Toml))
.unwrap();
let config = MinerConfig::load_from(&cfg).expect("Failed to load config");
assert_eq!(config.num_mining_threads, 2);
assert_eq!(
config.base_node_grpc_address,
Some("http://my_base_node:1234".to_string())
);
assert!(!config.mine_on_tip_only);
}
}

View File

@ -0,0 +1,163 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::convert::TryInto;
use minotari_app_grpc::tari_rpc::BlockHeader as grpc_header;
use tari_common_types::types::FixedHash;
use tari_core::{
blocks::BlockHeader,
proof_of_work::{randomx_factory::RandomXFactory, sha3x_difficulty, tari_randomx_difficulty},
};
use tari_utilities::epoch_time::EpochTime;
use crate::errors::MinerError;
pub type Difficulty = u64;
#[derive(Clone)]
pub struct BlockHeaderSha3 {
pub header: BlockHeader,
pub hashes: u64,
pub vm_key: FixedHash,
pub rx_factory: Option<RandomXFactory>,
}
impl BlockHeaderSha3 {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
pub fn new(header: grpc_header, vm_key: FixedHash, rx_factory: Option<RandomXFactory>) -> Result<Self, MinerError> {
let header: BlockHeader = header.try_into().map_err(MinerError::BlockHeader)?;
Ok(Self {
header,
hashes: 0,
vm_key,
rx_factory,
})
}
/// This function will update the timestamp of the header, but only if the new timestamp is greater than the current
/// one.
pub fn set_forward_timestamp(&mut self, timestamp: u64) {
// if the timestamp has been advanced by the base_node due to the median time we should not reverse it but we
// should only change the timestamp if we move it forward.
if timestamp > self.header.timestamp.as_u64() {
self.header.timestamp = EpochTime::from(timestamp);
}
}
pub fn random_nonce(&mut self) {
use rand::{rngs::OsRng, RngCore};
self.header.nonce = OsRng.next_u64();
}
#[inline]
pub fn inc_nonce(&mut self) {
self.header.nonce = self.header.nonce.wrapping_add(1);
}
#[inline]
pub fn difficulty_sha3(&mut self) -> Result<Difficulty, MinerError> {
self.hashes = self.hashes.saturating_add(1);
Ok(sha3x_difficulty(&self.header)?.as_u64())
}
#[inline]
pub fn difficulty_rx(&mut self) -> Result<Difficulty, MinerError> {
self.hashes = self.hashes.saturating_add(1);
let randomx_factory = self.rx_factory.as_ref().ok_or(MinerError::RandomXFactoryNotSet)?;
Ok(tari_randomx_difficulty(&self.header, randomx_factory, &self.vm_key)?.as_u64())
}
#[allow(clippy::cast_possible_wrap)]
pub fn create_header(&self) -> grpc_header {
self.header.clone().into()
}
#[inline]
pub fn height(&self) -> u64 {
self.header.height
}
}
#[cfg(test)]
pub mod test {
use chrono::{DateTime, NaiveDate, Utc};
use tari_core::proof_of_work::sha3x_difficulty as core_sha3x_difficulty;
use super::*;
#[allow(clippy::cast_sign_loss)]
pub fn get_header() -> (grpc_header, BlockHeader) {
let mut header = BlockHeader::new(0);
header.timestamp = (DateTime::<Utc>::from_naive_utc_and_offset(
NaiveDate::from_ymd_opt(2000, 1, 1)
.unwrap()
.and_hms_opt(1, 1, 1)
.unwrap(),
Utc,
)
.timestamp() as u64)
.into();
header.pow.pow_algo = tari_core::proof_of_work::PowAlgorithm::Sha3x;
(header.clone().into(), header)
}
#[test]
fn validate_nonce_difficulty() {
let (mut header, mut core_header) = get_header();
header.nonce = 1;
core_header.nonce = 1;
let mut hasher = BlockHeaderSha3::new(header, FixedHash::zero(), None).unwrap();
for _ in 0..1000 {
assert_eq!(
hasher.difficulty_sha3().unwrap(),
core_sha3x_difficulty(&core_header).unwrap().as_u64(),
"with nonces = {}:{}",
hasher.header.nonce,
core_header.nonce
);
core_header.nonce += 1;
hasher.inc_nonce();
}
}
#[test]
fn validate_timestamp_difficulty() {
let (mut header, mut core_header) = get_header();
header.nonce = 1;
core_header.nonce = 1;
let mut hasher = BlockHeaderSha3::new(header, FixedHash::zero(), None).unwrap();
let mut timestamp = core_header.timestamp;
for _ in 0..1000 {
assert_eq!(
hasher.difficulty_sha3().unwrap(),
core_sha3x_difficulty(&core_header).unwrap().as_u64(),
"with timestamp = {}",
timestamp
);
timestamp = timestamp.checked_add(EpochTime::from(1)).unwrap();
core_header.timestamp = timestamp;
hasher.set_forward_timestamp(timestamp.as_u64());
}
}
}

View File

@ -0,0 +1,72 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use minotari_app_grpc::authentication::BasicAuthError;
use minotari_app_utilities::parse_miner_input::ParseInputError;
use tari_max_size::MaxSizeBytesError;
use thiserror::Error;
use tonic::codegen::http::uri::InvalidUri;
#[derive(Debug, Error)]
pub enum MinerError {
#[error("I/O error")]
IOError(#[from] std::io::Error),
#[error("gRPC error: {0}")]
GrpcStatus(#[from] tonic::Status),
#[error("Connection error: {0}")]
GrpcConnection(#[from] tonic::transport::Error),
#[error("Node not ready")]
NodeNotReady,
#[error("Blockchain reached specified height {0}, mining will be stopped")]
MineUntilHeightReached(u64),
#[error("Block height {0} already mined")]
MinerLostBlock(u64),
#[error("Expected non empty {0}")]
EmptyObject(String),
#[error("Invalid block header {0}")]
BlockHeader(String),
#[error("Conversion error: {0}")]
Conversion(String),
#[error("Invalid gRPC credentials: {0}")]
BasicAuthError(#[from] BasicAuthError),
#[error("Invalid gRPC url: {0}")]
InvalidUri(#[from] InvalidUri),
#[error("TLS connection error: {0}")]
TlsConnectionError(String),
#[error("Coinbase error: {0}")]
CoinbaseError(String),
#[error("Consensus build error: {0}")]
ParseInputError(#[from] ParseInputError),
#[error("Base node not responding to gRPC requests: {0}")]
BaseNodeNotResponding(String),
#[error("Limit error {0}")]
MaxSizeBytesError(#[from] MaxSizeBytesError),
#[error("Miner is set to use Rx, but not RX factory is set")]
RandomXFactoryNotSet,
#[error("RandomX error: {0}")]
MergeMineError(#[from] tari_core::proof_of_work::monero_rx::MergeMineError),
#[error("Difficulty error: {0}")]
DifficultyError(#[from] tari_core::proof_of_work::DifficultyError),
}
pub fn err_empty(name: &str) -> MinerError {
MinerError::EmptyObject(name.to_string())
}

View File

@ -0,0 +1,39 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// non-64-bit not supported
minotari_app_utilities::deny_non_64_bit_archs!();
mod cli;
pub use cli::Cli;
use tari_common::exit_codes::ExitError;
mod run_miner;
use run_miner::start_miner;
mod config;
mod difficulty;
mod errors;
mod miner;
mod stratum;
pub async fn run_miner(cli: Cli) -> Result<(), ExitError> {
start_miner(cli).await
}

View File

@ -0,0 +1,76 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::io::stdout;
use clap::Parser;
use crossterm::{execute, terminal::SetTitle};
use log::*;
use minotari_app_utilities::consts;
use run_miner::start_miner;
use tari_common::{exit_codes::ExitError, initialize_logging};
use crate::cli::Cli;
pub const LOG_TARGET: &str = "minotari::miner::main";
pub const LOG_TARGET_FILE: &str = "minotari::logging::miner::main";
mod cli;
mod config;
mod difficulty;
mod errors;
mod miner;
mod run_miner;
mod stratum;
/// Application entry point
#[tokio::main]
async fn main() {
let terminal_title = format!("Minotari Miner - Version {}", consts::APP_VERSION);
if let Err(e) = execute!(stdout(), SetTitle(terminal_title.as_str())) {
println!("Error setting terminal title. {}", e)
}
match main_inner().await {
Ok(_) => std::process::exit(0),
Err(err) => {
error!(target: LOG_TARGET, "Fatal error: {}", err);
let exit_code = err.exit_code;
error!(target: LOG_TARGET, "Exiting with code: {}", exit_code);
std::process::exit(exit_code as i32)
},
}
}
async fn main_inner() -> Result<(), ExitError> {
let cli = Cli::parse();
initialize_logging(
&cli.common.log_config_path("miner"),
&cli.common.get_base_path(),
include_str!("../log4rs_sample.yml"),
)?;
info!(
target: LOG_TARGET,
"Starting Minotari Miner version: {}",
consts::APP_VERSION
);
start_miner(cli).await
}

View File

@ -0,0 +1,505 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::{
panic::panic_any,
pin::Pin,
task::{Context, Poll, Waker},
thread,
time::{Duration, Instant},
};
use chrono::Utc;
use crossbeam::channel::{bounded, Select, Sender, TrySendError};
use futures::Stream;
use log::*;
use minotari_app_grpc::tari_rpc::BlockHeader;
use tari_common_types::types::FixedHash;
use tari_core::proof_of_work::randomx_factory::RandomXFactory;
use thread::JoinHandle;
use super::difficulty::BlockHeaderSha3;
use zmq::{Socket};
use anyhow::{Result};
use serde::{Serialize, Deserialize};
use std::sync::{Arc};
use tokio::sync::{Mutex, };
use minotari_app_utilities::parse_miner_input::BaseNodeGrpcClient;
use crate::errors::MinerError;
pub const LOG_TARGET: &str = "minotari::miner::standalone";
// Identify how often mining thread is reporting / checking context
// ~400_000 hashes per second
const REPORTING_FREQUENCY_RX: u64 = 300;
const REPORTING_FREQUENCY_SHA3: u64 = 3_000_000;
// Thread's stack size, ideally we would fit all thread's data in the CPU L1 cache
const STACK_SIZE: usize = 320_000;
/// Miner will send regular reports from every mining threads
#[derive(Debug)]
pub struct MiningReport {
pub miner: usize,
pub target_difficulty: u64,
pub difficulty: u64,
pub hashes: u64,
pub elapsed: Duration,
/// Will be set for when mined header is matching required difficulty
pub header: Option<BlockHeader>,
pub height: u64,
}
/// Miner is starting number of mining threads and implements Stream for async reports polling
/// Communication with async world is performed via channel and waker so should be quite efficient
pub struct Miner {
threads: Vec<JoinHandle<()>>,
channels: Vec<crossbeam::channel::Receiver<MiningReport>>,
num_threads: usize,
header: BlockHeader,
target_difficulty: u64,
share_mode: bool,
vm_key: FixedHash,
rx_factory: Option<RandomXFactory>,
publisher_socket: Arc<Mutex<Socket>>,
subscriber_socket: Arc<Mutex<Socket>>,
base_node_client: BaseNodeGrpcClient,
}
impl Miner {
pub fn init_mining(
base_node_client: BaseNodeGrpcClient,
header: BlockHeader,
target_difficulty: u64,
num_threads: usize,
share_mode: bool,
vm_key: FixedHash,
rx_factory: Option<RandomXFactory>,
publisher_socket: Arc<Mutex<Socket>>,
subscriber_socket: Arc<Mutex<Socket>>,
) -> Self {
Self {
threads: vec![],
channels: vec![],
header,
num_threads,
target_difficulty,
share_mode,
vm_key,
rx_factory,
publisher_socket,
subscriber_socket,
base_node_client,
}
}
// this will kill all mining threads currently active and attached to this miner
pub fn kill_threads(&mut self) {
self.channels.clear();
}
// Start mining threads with async context waker
fn start_threads(&mut self, ctx: &Context<'_>) {
let miners = (0..self.num_threads)
.map(|i| {
(
thread::Builder::new()
.name(format!("cpu-miner-{}", i))
.stack_size(STACK_SIZE),
i,
)
})
.map(|(thread, i)| {
let (tx, rx) = bounded(1);
let header = self.header.clone();
let waker = ctx.waker().clone();
let difficulty = self.target_difficulty;
let share_mode = self.share_mode;
let vm_key = self.vm_key;
let rx_factory = self.rx_factory.clone();
let pub_socket = Arc::clone(&self.publisher_socket);
let sub_socket = Arc::clone(&self.subscriber_socket);
let base_node_client_clone = self.base_node_client.clone();
let handle = thread
.spawn(move || mining_task(base_node_client_clone, header, difficulty, tx, waker, i, share_mode, vm_key, rx_factory, pub_socket, sub_socket))
.expect("Failed to create mining thread");
(handle, rx)
});
let (threads, channels) = miners.unzip();
self.threads = threads;
self.channels = channels;
}
}
impl Stream for Miner {
type Item = MiningReport;
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
trace!(target: LOG_TARGET, "Polling Miner");
// First poll would start all the threads passing async context waker
if self.threads.is_empty() && self.num_threads > 0 {
debug!(
target: LOG_TARGET,
"Starting {} mining threads for target difficulty {}", self.num_threads, self.target_difficulty
);
self.start_threads(ctx);
return Poll::Pending;
} else if self.num_threads == 0 {
error!(target: LOG_TARGET, "Cannot mine: no mining threads");
return Poll::Ready(None);
} else if self.channels.is_empty() {
debug!(target: LOG_TARGET, "Finished mining");
return Poll::Ready(None);
} else {
// do nothing
}
// Non blocking select from all miner's receiver channels
let mut sel = Select::new();
for rx in &self.channels {
sel.recv(rx);
}
let report = match sel.try_select() {
Ok(oper) => {
let idx = oper.index();
match oper.recv(&self.channels[idx]) {
Ok(report) => report,
Err(_) => {
// Received error would mean thread is disconnected already
trace!("Thread {} disconnected.", idx);
return Poll::Ready(None);
},
}
},
Err(_) => {
// No reports
return Poll::Pending;
},
};
if report.header.is_some() && !self.share_mode {
// Dropping recipients would stop miners next time they try to report
self.channels.clear();
}
Poll::Ready(Some(report))
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GbtMsg {
pub height: u64,
pub header: String,
pub u64target: u64,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SubmitRequest {
pub id: u64,
pub user: String,
pub miner: String,
pub index: String,
pub header: String,
pub nonce: u64,
pub pow: String,
pub subidx: i64,
pub height: u64,
pub submitidx: u64,
}
fn send_gbt_message(socket: &Arc<Mutex<Socket>>, msg: &GbtMsg) -> Result<(), Box<dyn std::error::Error>> {
let msg_json = serde_json::to_string(msg)?;
if let Ok(pub_socket) = socket.try_lock() {
pub_socket.send_multipart(&["jobsha3x".as_bytes(), msg_json.as_bytes()], 0)?;
println!("send_gbt_message");
Ok(())
} else {
Err("Socket lock busy".into())
}
}
fn try_receive_nonce(socket: &Arc<Mutex<Socket>>) -> Option<u64> {
let sub_socket = match socket.try_lock() {
Ok(sub_socket) => sub_socket,
Err(_) => return None,
};
sub_socket.set_rcvtimeo(100).expect("Set timeout failed");
let frames = match sub_socket.recv_multipart(zmq::DONTWAIT) {
Ok(frames) => frames,
Err(zmq::Error::EAGAIN) => return None,
Err(e) => {
error!("ZMQ receive error: {}", e);
return None;
}
};
drop(sub_socket);
if frames.len() < 2 {
warn!("Invalid message format: expected at least 2 frames");
return None;
}
//println!("First frame: {:?}", frames.first().unwrap().as_slice());
//println!("Nonce frame: {:?}", &frames[1]);
if frames.first().map(Vec::as_slice) != Some(b"blksha3x") {
return None;
}
match serde_json::from_slice::<SubmitRequest>(&frames[1]) {
Ok(request) => Some(request.nonce),
Err(e) => {
warn!("Failed to parse nonce: {}", e);
None
}
}
}
/// Miner starts with a random nonce and iterates until it finds a header hash that meets the desired
/// target
pub fn mining_task(
mut node_conn: BaseNodeGrpcClient,
header: BlockHeader,
target_difficulty: u64,
sender: Sender<MiningReport>,
waker: Waker,
miner: usize,
share_mode: bool,
vm_key: FixedHash,
rx_factory: Option<RandomXFactory>,
publisher_socket: Arc<Mutex<Socket>>,
subscriber_socket: Arc<Mutex<Socket>>,
) {
let mining_algorithm = if rx_factory.is_some() { "RandomXT" } else { "Sha3X" };
let start = Instant::now();
let mut hasher = match BlockHeaderSha3::new(header, vm_key, rx_factory) {
Ok(hasher) => hasher,
Err(err) => {
let err = format!(
"Miner {} on {} failed to create hasher: {:?}",
miner, mining_algorithm, err
);
error!(target: LOG_TARGET, "{}", err);
panic_any(err);
},
};
hasher.random_nonce();
let gbt_msg = GbtMsg {
height: hasher.header.height,
header: hasher.header.mining_hash().to_string(),
u64target: target_difficulty,
};
if let Err(e) = send_gbt_message(&publisher_socket, &gbt_msg) {
error!(
target: LOG_TARGET,
"Miner {} failed to send GBT message: {}", miner, e
);
}
// We're mining over here!
trace!(target: LOG_TARGET, "Mining thread {} started for {}", miner, mining_algorithm);
let mut check_count:u64 = 0;
// Mining work
loop {
if let Some(nonce) = try_receive_nonce(&subscriber_socket) {
check_count = 0;
hasher.header.nonce = nonce;
println!("nonce {} {}", nonce, hasher.header.nonce);
trace!(
target: LOG_TARGET,
"Miner {} received new nonce: {}", miner, nonce
);
} else {
check_count += 1;
if check_count > 10 {
check_count = 0;
let result = futures::executor::block_on(validate_tip(&mut node_conn, hasher.header.height));
match result {
Ok(()) => {}
Err(e) => {
error!("Tip validation error: {:?}", e);
let difficulty = 0;
let res = sender.try_send(MiningReport {
miner,
difficulty,
hashes: hasher.hashes,
elapsed: start.elapsed(),
header: None,
height: hasher.height(),
target_difficulty,
});
waker.wake_by_ref();
trace!(target: LOG_TARGET, "Reporting from {} on {} result {:?}", miner, mining_algorithm, res);
if let Err(TrySendError::Disconnected(_)) = res {
info!(target: LOG_TARGET, "Mining thread {} on {} disconnected", miner, mining_algorithm);
return;
}
return;
}
}
}
/*check_count += 1;
let reporting_frequency = if hasher.rx_factory.is_some() {
REPORTING_FREQUENCY_RX
} else {
REPORTING_FREQUENCY_SHA3
};
if check_count > reporting_frequency {
check_count = 0;
let difficulty = 0;
let res = sender.try_send(MiningReport {
miner,
difficulty,
hashes: hasher.hashes,
elapsed: start.elapsed(),
header: None,
height: hasher.height(),
target_difficulty,
});
waker.wake_by_ref();
trace!(target: LOG_TARGET, "Reporting from {} on {} result {:?}", miner, mining_algorithm, res);
if let Err(TrySendError::Disconnected(_)) = res {
info!(target: LOG_TARGET, "Mining thread {} on {} disconnected", miner, mining_algorithm);
return;
}
}*/
continue;
}
println!("get nonce {}", hasher.header.nonce);
let hashed = if hasher.rx_factory.is_some() {
hasher.difficulty_rx()
} else {
println!("calc diff sha3x");
hasher.difficulty_sha3()
};
println!("check diff");
let difficulty = match hashed {
Ok(difficulty) => difficulty,
Err(err) => {
let err = format!(
"Miner {} failed to calculate difficulty on {}: {:?}",
miner, mining_algorithm, err
);
error!(target: LOG_TARGET, "{}", err);
panic_any(err);
},
};
println!("difficulty {},{}", difficulty, target_difficulty);
if difficulty >= target_difficulty {
debug!(
target: LOG_TARGET,
"Miner {} found nonce {} with matching difficulty {} on {} height {}",
miner, hasher.header.nonce, difficulty, mining_algorithm, hasher.header.height
);
println!(
"Miner {} found nonce {} with matching difficulty {} on {} height {}",
miner, hasher.header.nonce, difficulty, mining_algorithm, hasher.header.height
);
if let Err(err) = sender.try_send(MiningReport {
miner,
difficulty,
hashes: hasher.hashes,
elapsed: start.elapsed(),
height: hasher.height(),
header: Some(hasher.create_header()),
target_difficulty,
}) {
error!(target: LOG_TARGET, "Miner {} on {} failed to send report: {}", miner, mining_algorithm, err);
}
// If we are mining in share mode, this share might not be a block, so we need to keep mining till we get a
// new job
if share_mode {
waker.wake_by_ref();
} else {
waker.wake();
trace!(target: LOG_TARGET, "Mining thread {} on {} stopped", miner, mining_algorithm);
println!("Mining thread {} on {} stopped", miner, mining_algorithm);
return;
}
}
let reporting_frequency = if hasher.rx_factory.is_some() {
REPORTING_FREQUENCY_RX
} else {
REPORTING_FREQUENCY_SHA3
};
if hasher.header.nonce % reporting_frequency == 0 {
let res = sender.try_send(MiningReport {
miner,
difficulty,
hashes: hasher.hashes,
elapsed: start.elapsed(),
header: None,
height: hasher.height(),
target_difficulty,
});
waker.wake_by_ref();
trace!(target: LOG_TARGET, "Reporting from {} on {} result {:?}", miner, mining_algorithm, res);
if let Err(TrySendError::Disconnected(_)) = res {
info!(target: LOG_TARGET, "Mining thread {} on {} disconnected", miner, mining_algorithm);
return;
}
/*if !(share_mode) {
hasher.set_forward_timestamp(Utc::now().timestamp() as u64);
}*/
}
//hasher.inc_nonce();
}
}
async fn validate_tip(
node_conn: &mut BaseNodeGrpcClient,
height: u64,
) -> Result<(), MinerError> {
let tip = node_conn
.get_tip_info(minotari_app_grpc::tari_rpc::Empty {})
.await?
.into_inner();
let longest_height = tip.clone().metadata.unwrap().best_block_height;
if height <= longest_height {
return Err(MinerError::MinerLostBlock(height));
}
if !tip.initial_sync_achieved || tip.metadata.is_none() {
return Err(MinerError::NodeNotReady);
}
if height <= longest_height {
return Err(MinerError::MinerLostBlock(height));
}
Ok(())
}

View File

@ -0,0 +1,735 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::{convert::TryFrom, sync::Arc, thread, time::Instant};
use futures::stream::StreamExt;
use log::*;
use minotari_app_grpc::{
authentication::ClientAuthenticationInterceptor,
conversions::transaction_output::grpc_output_with_payref,
tari_rpc::{
base_node_client::BaseNodeClient,
pow_algo::PowAlgos,
sha_p2_pool_client::ShaP2PoolClient,
Block,
GetNewBlockRequest,
PowAlgo,
SubmitBlockRequest,
SubmitBlockResponse,
},
};
use minotari_app_utilities::parse_miner_input::{
prompt_for_base_node_address,
prompt_for_p2pool_address,
verify_base_node_grpc_mining_responses,
wallet_payment_address,
BaseNodeGrpcClient,
ShaP2PoolGrpcClient,
};
use tari_common::{
exit_codes::{ExitCode, ExitError},
load_configuration,
DefaultConfigLoader,
MAX_GRPC_MESSAGE_SIZE,
};
use tari_common_types::{
tari_address::TariAddress,
types::{FixedHash, UncompressedPublicKey},
};
use tari_core::{
blocks::BlockHeader,
consensus::ConsensusManager,
proof_of_work::{randomx_factory::RandomXFactory, PowAlgorithm},
transactions::{
generate_coinbase,
tari_amount::MicroMinotari,
transaction_components::{
payment_id::{PaymentId, TxType},
CoinBaseExtra,
},
transaction_key_manager::{create_memory_db_key_manager, MemoryDbKeyManager},
},
};
use tari_utilities::hex::Hex;
use tokio::{sync::Mutex, time::sleep};
use tonic::transport::{Certificate, ClientTlsConfig, Endpoint};
use zmq::{Context as ZmqContext, Socket, SUB};
use anyhow::anyhow;
use anyhow::{Context, Result};
use crate::{
cli::Cli,
config::MinerConfig,
errors::{err_empty, MinerError},
miner::{Miner, MiningReport},
stratum::stratum_controller::controller::Controller,
};
pub const LOG_TARGET: &str = "minotari::miner::main";
pub const LOG_TARGET_FILE: &str = "minotari::logging::miner::main";
#[allow(clippy::too_many_lines)]
pub async fn start_miner(cli: Cli) -> Result<(), ExitError> {
let config_path = cli.common.config_path();
let cfg = load_configuration(
config_path.as_path(),
true,
cli.non_interactive_mode,
&cli,
cli.common.network,
)?;
let mut config = MinerConfig::load_from(&cfg).expect("Failed to load config");
config.set_base_path(cli.common.get_base_path());
debug!(target: LOG_TARGET_FILE, "{:?}", config);
let key_manager = create_memory_db_key_manager().map_err(|err| {
ExitError::new(
ExitCode::KeyManagerServiceError,
"'wallet_payment_address' ".to_owned() + &err.to_string(),
)
})?;
let wallet_payment_address = wallet_payment_address(config.wallet_payment_address.clone(), config.network)
.map_err(|err| {
ExitError::new(
ExitCode::WalletPaymentAddress,
"'wallet_payment_address' ".to_owned() + &err.to_string(),
)
})?;
debug!(target: LOG_TARGET_FILE, "wallet_payment_address: {}", wallet_payment_address);
let consensus_manager = ConsensusManager::builder(config.network)
.build()
.map_err(|err| ExitError::new(ExitCode::ConsensusManagerBuilderError, err.to_string()))?;
if !config.stratum_mining_wallet_address.is_empty() && !config.stratum_mining_pool_address.is_empty() {
let url = config.stratum_mining_pool_address.clone();
let mut miner_address = config.stratum_mining_wallet_address.clone();
let _unused = UncompressedPublicKey::from_hex(&miner_address).map_err(|_| {
ExitError::new(
ExitCode::ConfigError,
"Miner is not configured with a valid wallet address.",
)
})?;
if !config.mining_worker_name.is_empty() {
miner_address += &format!("{}{}", ".", config.mining_worker_name);
}
let mut mc = Controller::new(config.num_mining_threads).map_err(|e| {
debug!(target: LOG_TARGET_FILE, "Error loading mining controller: {}", e);
ExitError::new(
ExitCode::UnknownError,
format!("Error loading mining controller: {}", e),
)
})?;
let cc = crate::stratum::controller::Controller::new(&url, Some(miner_address), None, None, mc.tx.clone())
.map_err(|e| {
debug!(
target: LOG_TARGET_FILE,
"Error loading stratum client controller: {:?}", e
);
ExitError::new(
ExitCode::UnknownError,
format!("Error loading mining controller: {}", e),
)
})?;
mc.set_client_tx(cc.tx.clone());
let _join_handle = thread::Builder::new()
.name("client_controller".to_string())
.spawn(move || {
cc.run();
});
mc.run()
.await
.map_err(|err| ExitError::new(ExitCode::UnknownError, format!("Stratum error: {:?}", err)))?;
Ok(())
} else {
let node_clients = connect(&config)
.await
.map_err(|e| ExitError::new(ExitCode::GrpcError, e.to_string()))?;
let mut base_node_client = node_clients.base_node_client;
let mut p2pool_node_client = node_clients.p2pool_node_client;
if let Err(e) = verify_base_node_responses(&mut base_node_client, &config).await {
if let MinerError::BaseNodeNotResponding(_) = e {
error!(target: LOG_TARGET, "{}", e);
println!();
let msg = "Could not connect to the base node. \nAre the base node's gRPC mining methods allowed in \
its 'config.toml'? Please ensure these methods are enabled in:\n \
'grpc_server_allow_methods': \"get_new_block_template\", \"get_tip_info\", \
\"get_new_block\", \"submit_block\"";
println!("{}", msg);
println!();
return Err(ExitError::new(ExitCode::GrpcError, e.to_string()));
}
}
config.zmq_publisher_port = 11113;
config.zmq_subscriber_port = 11112;
println!("pub port:{}, sub port {}", config.zmq_publisher_port, config.zmq_subscriber_port);
let zmq_context = ZmqContext::new();
let publisher_socket = zmq_context
.socket(zmq::PUB)
.map_err(|e| anyhow!("ZMQ publisher error: {}", e))?;
let publisher_addr = format!("tcp://0.0.0.0:{}", config.zmq_publisher_port);
println!("publisher_addr:{}",publisher_addr);
publisher_socket
.bind(&publisher_addr)
.map_err(|e| anyhow!("ZMQ bind error: {}", e))?;
let subscriber_socket = zmq_context
.socket(SUB)
.context("Failed to create SUB socket")?;
let subscriber_addr = format!("tcp://172.17.0.1:{}", config.zmq_subscriber_port);
println!("subscriber_addr:{}",subscriber_addr);
subscriber_socket
.connect(&subscriber_addr)
.context("Failed to connect to PUB server")?;
subscriber_socket
.set_subscribe(b"")
.context("Failed to subscribe to all messages")?;
let publisher = Arc::new(Mutex::new(publisher_socket));
let subscriber = Arc::new(Mutex::new(subscriber_socket));
let mut blocks_found: u64 = 0;
loop {
debug!(target: LOG_TARGET, "Starting new mining cycle");
match mining_cycle(
&mut base_node_client,
p2pool_node_client.clone(),
&config,
&cli,
&key_manager,
&wallet_payment_address,
&consensus_manager,
publisher.clone(),
subscriber.clone(),
)
.await
{
err @ Err(MinerError::GrpcConnection(_)) | err @ Err(MinerError::GrpcStatus(_)) => {
// Any GRPC error we will try to reconnect with a standard delay
error!(target: LOG_TARGET, "Connection error: {:?}", err);
loop {
info!(target: LOG_TARGET, "Holding for {:?}", config.wait_timeout());
sleep(config.wait_timeout()).await;
match connect(&config).await {
Ok(nc) => {
base_node_client = nc.base_node_client;
p2pool_node_client = nc.p2pool_node_client;
break;
},
Err(err) => {
error!(target: LOG_TARGET, "Connection error: {:?}", err);
continue;
},
}
}
},
Err(MinerError::MineUntilHeightReached(h)) => {
warn!(
target: LOG_TARGET,
"Prescribed blockchain height {} reached. Aborting ...", h
);
return Ok(());
},
Err(MinerError::MinerLostBlock(h)) => {
warn!(
target: LOG_TARGET,
"Height {} already mined by other node. Restarting ...", h
);
},
Err(err) => {
error!(target: LOG_TARGET, "Error: {:?}", err);
sleep(config.wait_timeout()).await;
},
Ok(submitted) => {
info!(target: LOG_TARGET, "💰 Found block");
if submitted {
blocks_found += 1;
}
println!("blocks_found: {} {}", blocks_found, cli.miner_max_blocks.unwrap_or(0));
if let Some(max_blocks) = cli.miner_max_blocks {
if blocks_found >= max_blocks {
println!("blocks_found >= max_blocks exit");
return Ok(());
}
}
},
}
}
}
}
pub struct NodeClientResult {
base_node_client: BaseNodeGrpcClient,
p2pool_node_client: Option<ShaP2PoolGrpcClient>,
}
async fn connect(config: &MinerConfig) -> Result<NodeClientResult, MinerError> {
// always connect to base node first
let base_node_client = match connect_base_node(config).await {
Ok(client) => client,
Err(e) => {
error!(target: LOG_TARGET, "Could not connect to base node: {}", e);
let msg = "Could not connect to base node. \nIs the base node's gRPC running? Try running it with \
`--enable-grpc` or enable it in the config.";
println!("{}", msg);
return Err(e);
},
};
// init client to sha p2pool grpc if enabled
let mut p2pool_node_client = None;
if config.sha_p2pool_enabled {
p2pool_node_client = match connect_sha_p2pool(config).await {
Ok(client) => Some(client),
Err(e) => {
error!(target: LOG_TARGET, "Could not connect to base node: {}", e);
let msg = "Could not connect to base node. \nIs the base node's gRPC running? Try running it with \
`--enable-grpc` or enable it in the config.";
println!("{}", msg);
return Err(e);
},
};
}
Ok(NodeClientResult {
base_node_client,
p2pool_node_client,
})
}
async fn connect_sha_p2pool(config: &MinerConfig) -> Result<ShaP2PoolGrpcClient, MinerError> {
let p2pool_node_addr;
if let Some(ref a) = config.base_node_grpc_address {
p2pool_node_addr = a.clone();
} else {
p2pool_node_addr = prompt_for_p2pool_address()?;
}
info!(target: LOG_TARGET, "👛 Connecting to p2pool node at {}", p2pool_node_addr);
let mut endpoint = Endpoint::new(p2pool_node_addr)?;
if let Some(domain_name) = config.base_node_grpc_tls_domain_name.as_ref() {
let pem = tokio::fs::read(config.config_dir.join(&config.base_node_grpc_ca_cert_filename))
.await
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
let ca = Certificate::from_pem(pem);
let tls = ClientTlsConfig::new().ca_certificate(ca).domain_name(domain_name);
endpoint = endpoint
.tls_config(tls)
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
}
let channel = endpoint
.connect()
.await
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
let node_conn = ShaP2PoolClient::with_interceptor(
channel,
ClientAuthenticationInterceptor::create(&config.base_node_grpc_authentication)?,
)
.max_encoding_message_size(MAX_GRPC_MESSAGE_SIZE)
.max_decoding_message_size(MAX_GRPC_MESSAGE_SIZE);
Ok(node_conn)
}
async fn connect_base_node(config: &MinerConfig) -> Result<BaseNodeGrpcClient, MinerError> {
let base_node_addr;
if let Some(ref a) = config.base_node_grpc_address {
base_node_addr = a.clone();
} else {
base_node_addr = prompt_for_base_node_address(config.network)?;
}
info!(target: LOG_TARGET, "👛 Connecting to base node at {}", base_node_addr);
let mut endpoint = Endpoint::new(base_node_addr)?;
if let Some(domain_name) = config.base_node_grpc_tls_domain_name.as_ref() {
let pem = tokio::fs::read(config.config_dir.join(&config.base_node_grpc_ca_cert_filename))
.await
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
let ca = Certificate::from_pem(pem);
let tls = ClientTlsConfig::new().ca_certificate(ca).domain_name(domain_name);
endpoint = endpoint
.tls_config(tls)
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
}
let channel = endpoint
.connect()
.await
.map_err(|e| MinerError::TlsConnectionError(e.to_string()))?;
let node_conn = BaseNodeClient::with_interceptor(
channel,
ClientAuthenticationInterceptor::create(&config.base_node_grpc_authentication)?,
)
.max_encoding_message_size(MAX_GRPC_MESSAGE_SIZE)
.max_decoding_message_size(MAX_GRPC_MESSAGE_SIZE);
Ok(node_conn)
}
async fn verify_base_node_responses(
node_conn: &mut BaseNodeGrpcClient,
config: &MinerConfig,
) -> Result<(), MinerError> {
if let Err(e) = verify_base_node_grpc_mining_responses(node_conn, config.pow_algo_request()).await {
return Err(MinerError::BaseNodeNotResponding(e));
}
Ok(())
}
struct GetNewBlockResponse {
block: Block,
target_difficulty: u64,
vm_key: FixedHash,
}
/// Gets a new block from base node or p2pool node if its enabled in config
async fn get_new_block(
base_node_client: &mut BaseNodeGrpcClient,
sha_p2pool_client: Arc<Mutex<Option<ShaP2PoolGrpcClient>>>,
config: &MinerConfig,
cli: &Cli,
key_manager: &MemoryDbKeyManager,
wallet_payment_address: &TariAddress,
consensus_manager: &ConsensusManager,
) -> Result<GetNewBlockResponse, MinerError> {
if config.sha_p2pool_enabled {
if let Some(client) = sha_p2pool_client.lock().await.as_mut() {
return get_new_block_p2pool_node(config, client, wallet_payment_address).await;
}
}
get_new_block_base_node(
base_node_client,
config,
cli,
key_manager,
wallet_payment_address,
consensus_manager,
)
.await
}
async fn get_new_block_base_node(
base_node_client: &mut BaseNodeGrpcClient,
config: &MinerConfig,
cli: &Cli,
key_manager: &MemoryDbKeyManager,
wallet_payment_address: &TariAddress,
consensus_manager: &ConsensusManager,
) -> Result<GetNewBlockResponse, MinerError> {
debug!(target: LOG_TARGET, "Getting new block template");
let template_response = base_node_client
.get_new_block_template(config.pow_algo_request())
.await?
.into_inner();
let mut block_template = template_response
.new_block_template
.clone()
.ok_or_else(|| err_empty("new_block_template"))?;
let height = block_template
.header
.as_ref()
.ok_or_else(|| err_empty("header"))?
.height;
if config.mine_on_tip_only {
debug!(
target: LOG_TARGET,
"Checking if base node is synced, because mine_on_tip_only is true"
);
validate_tip(base_node_client, height, cli.mine_until_height).await?;
}
debug!(target: LOG_TARGET, "Getting coinbase");
let miner_data = template_response.miner_data.ok_or_else(|| err_empty("miner_data"))?;
let fee = MicroMinotari::from(miner_data.total_fees);
let reward = MicroMinotari::from(miner_data.reward);
let (coinbase_output, coinbase_kernel) = generate_coinbase(
fee,
reward,
height,
&CoinBaseExtra::try_from(config.coinbase_extra.as_bytes().to_vec())?,
key_manager,
wallet_payment_address,
true,
consensus_manager.consensus_constants(height),
config.range_proof_type,
PaymentId::Open {
user_data: vec![],
tx_type: TxType::Coinbase,
},
)
.await
.map_err(|e| MinerError::CoinbaseError(e.to_string()))?;
debug!(target: LOG_TARGET, "Coinbase kernel: {}", coinbase_kernel);
debug!(target: LOG_TARGET, "Coinbase output: {}", coinbase_output);
let body = block_template
.body
.as_mut()
.ok_or_else(|| err_empty("new_block_template.body"))?;
let grpc_output =
grpc_output_with_payref(coinbase_output.clone(), None).map_err(|e| MinerError::Conversion(e.to_string()))?;
body.outputs.push(grpc_output);
body.kernels.push(coinbase_kernel.into());
let target_difficulty = miner_data.target_difficulty;
debug!(target: LOG_TARGET, "Asking base node to assemble the MMR roots");
let block_result = base_node_client.get_new_block(block_template).await?.into_inner();
Ok(GetNewBlockResponse {
block: block_result.block.ok_or_else(|| err_empty("block"))?,
target_difficulty,
vm_key: FixedHash::try_from(block_result.vm_key).map_err(|_| MinerError::Conversion("vm_key".to_string()))?,
})
}
async fn get_new_block_p2pool_node(
config: &MinerConfig,
sha_p2pool_client: &mut ShaP2PoolGrpcClient,
wallet_payment_address: &TariAddress,
) -> Result<GetNewBlockResponse, MinerError> {
let pow_algo = PowAlgo {
pow_algo: PowAlgos::Sha3x.into(),
};
let coinbase_extra = if config.coinbase_extra.trim().is_empty() {
String::new()
} else {
config.coinbase_extra.clone()
};
let block_result = sha_p2pool_client
.get_new_block(GetNewBlockRequest {
pow: Some(pow_algo),
coinbase_extra,
wallet_payment_address: wallet_payment_address.to_base58(),
})
.await?
.into_inner();
let new_block_result = block_result.block.ok_or_else(|| err_empty("block result"))?;
let block = new_block_result.block.ok_or_else(|| err_empty("block response"))?;
Ok(GetNewBlockResponse {
block,
target_difficulty: block_result.target_difficulty,
vm_key: FixedHash::zero(),
})
}
async fn submit_block(
config: &MinerConfig,
base_node_client: &mut BaseNodeGrpcClient,
sha_p2pool_client: Option<&mut ShaP2PoolGrpcClient>,
block: Block,
wallet_payment_address: &TariAddress,
) -> Result<SubmitBlockResponse, MinerError> {
if config.sha_p2pool_enabled {
if let Some(client) = sha_p2pool_client {
return Ok(client
.submit_block(SubmitBlockRequest {
block: Some(block),
wallet_payment_address: wallet_payment_address.to_hex(),
})
.await
.map_err(MinerError::GrpcStatus)?
.into_inner());
}
}
Ok(base_node_client
.submit_block(block)
.await
.map_err(MinerError::GrpcStatus)?
.into_inner())
}
#[allow(clippy::too_many_lines)]
async fn mining_cycle(
base_node_client: &mut BaseNodeGrpcClient,
sha_p2pool_client: Option<ShaP2PoolGrpcClient>,
config: &MinerConfig,
cli: &Cli,
key_manager: &MemoryDbKeyManager,
wallet_payment_address: &TariAddress,
consensus_manager: &ConsensusManager,
publisher_socket: Arc<Mutex<Socket>>,
subscriber_socket: Arc<Mutex<Socket>>,
) -> Result<bool, MinerError> {
let sha_p2pool_client = Arc::new(Mutex::new(sha_p2pool_client));
let block_result = get_new_block(
base_node_client,
sha_p2pool_client.clone(),
config,
cli,
key_manager,
wallet_payment_address,
consensus_manager,
)
.await?;
let block = block_result.block;
let header = block.clone().header.ok_or_else(|| err_empty("block.header"))?;
debug!(target: LOG_TARGET, "Initializing miner");
let rx_factory = if config.proof_of_work_algo == PowAlgorithm::RandomXT {
Some(RandomXFactory::new(config.num_mining_threads))
} else {
None
};
let mut reports = Miner::init_mining(
base_node_client.clone(),
header.clone(),
block_result.target_difficulty,
config.num_mining_threads,
false,
block_result.vm_key,
rx_factory,
publisher_socket,
subscriber_socket,
);
let mut reporting_timeout = Instant::now();
let mut block_submitted = false;
while let Some(report) = reports.next().await {
if let Some(header) = report.header.clone() {
let mut submit = true;
if let Some(min_diff) = cli.miner_min_diff {
if report.difficulty < min_diff {
submit = false;
debug!(
target: LOG_TARGET_FILE,
"Mined difficulty {} below minimum difficulty {}. Not submitting.", report.difficulty, min_diff
);
}
}
if let Some(max_diff) = cli.miner_max_diff {
if report.difficulty > max_diff {
submit = false;
debug!(
target: LOG_TARGET_FILE,
"Mined difficulty {} greater than maximum difficulty {}. Not submitting.",
report.difficulty,
max_diff
);
}
}
if submit {
// Mined a block fitting the difficulty
let block_header = BlockHeader::try_from(header.clone()).map_err(MinerError::Conversion)?;
debug!(
target: LOG_TARGET,
"Miner found block header {} with difficulty {:?}", block_header, report.difficulty,
);
println!(
"Miner found block header {} with difficulty {:?}", block_header, report.difficulty,
);
let mut mined_block = block.clone();
mined_block.header = Some(header);
// 5. Sending block to the node
submit_block(
config,
base_node_client,
sha_p2pool_client.lock().await.as_mut(),
mined_block,
wallet_payment_address,
)
.await?;
block_submitted = true;
break;
} else {
display_report(&report, config.num_mining_threads).await;
}
} else {
display_report(&report, config.num_mining_threads).await;
}
//if config.mine_on_tip_only && reporting_timeout.elapsed() > config.validate_tip_interval() {
validate_tip(base_node_client, report.height, cli.mine_until_height).await?;
reporting_timeout = Instant::now();
//}
}
// Not waiting for threads to stop, they should stop in a short while after `reports` dropped
Ok(block_submitted)
}
pub async fn display_report(report: &MiningReport, num_mining_threads: usize) {
let mut hashrate = report.hashes as f64 / report.elapsed.as_secs() as f64;
let display_string = if hashrate > 1_000_000.0 {
hashrate /= 1_000_000.0;
"MH/s"
} else {
hashrate /= 1_000.0;
"KH/s"
};
info!(
target: LOG_TARGET,
"⛏ Miner {:0>2} reported {:.2}{} with total {:.2}{} over {} threads. Height: {}. Target: {})",
report.miner,
hashrate,
display_string,
hashrate * num_mining_threads as f64,
display_string,
num_mining_threads,
report.height,
report.target_difficulty,
);
}
/// If config
async fn validate_tip(
node_conn: &mut BaseNodeGrpcClient,
height: u64,
mine_until_height: Option<u64>,
) -> Result<(), MinerError> {
let tip = node_conn
.get_tip_info(minotari_app_grpc::tari_rpc::Empty {})
.await?
.into_inner();
let longest_height = tip.clone().metadata.unwrap().best_block_height;
if let Some(height) = mine_until_height {
if longest_height >= height {
return Err(MinerError::MineUntilHeightReached(height));
}
}
if height <= longest_height {
return Err(MinerError::MinerLostBlock(height));
}
if !tip.initial_sync_achieved || tip.metadata.is_none() {
return Err(MinerError::NodeNotReady);
}
if height <= longest_height {
return Err(MinerError::MinerLostBlock(height));
}
Ok(())
}

View File

@ -0,0 +1,419 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::{
io::{BufRead, ErrorKind, Write},
sync::mpsc,
thread,
time::{Duration, Instant},
};
use log::*;
use crate::stratum::{error::Error, stratum_types as types, stream::Stream};
pub const LOG_TARGET: &str = "minotari::miner::stratum::controller";
pub const LOG_TARGET_FILE: &str = "minotari::logging::miner::stratum::controller";
pub struct Controller {
server_url: String,
server_login: Option<String>,
server_password: Option<String>,
server_tls_enabled: Option<bool>,
stream: Option<Stream>,
rx: mpsc::Receiver<types::client_message::ClientMessage>,
pub tx: mpsc::Sender<types::client_message::ClientMessage>,
miner_tx: mpsc::Sender<types::miner_message::MinerMessage>,
last_request_id: String,
}
// fn invalid_error_response() -> types::RpcError {
// types::RpcError {
// code: 0,
// message: "Invalid error response received".to_owned(),
// }
// }
impl Controller {
pub fn new(
server_url: &str,
server_login: Option<String>,
server_password: Option<String>,
server_tls_enabled: Option<bool>,
miner_tx: mpsc::Sender<types::miner_message::MinerMessage>,
) -> Result<Controller, Error> {
let (tx, rx) = mpsc::channel::<types::client_message::ClientMessage>();
Ok(Controller {
server_url: server_url.to_string(),
server_login,
server_password,
server_tls_enabled,
stream: None,
tx,
rx,
miner_tx,
last_request_id: "".to_string(),
})
}
pub fn try_connect(&mut self) -> Result<(), Error> {
self.stream = None;
let stream = Stream::try_connect(&self.server_url, self.server_tls_enabled)?;
self.stream = Some(stream);
Ok(())
}
fn stream(&mut self) -> Result<&mut Stream, Error> {
self.stream.as_mut().ok_or(Error::NotConnected)
}
fn read_message(&mut self) -> Result<Option<String>, Error> {
let mut line = String::new();
match self.stream()?.read_line(&mut line) {
Ok(_) => {
// stream is not returning a proper error on disconnect
if line.is_empty() {
return Err(Error::Connection("broken pipe".to_string()));
}
Ok(Some(line))
},
Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Err(Error::Connection("broken pipe".to_string())),
Err(ref e) if e.kind() == ErrorKind::WouldBlock => Ok(None),
Err(e) => {
error!(target: LOG_TARGET, "Communication error with stratum server: {}", e);
Err(Error::Connection("broken pipe".to_string()))
},
}
}
fn send_message(&mut self, message: &str) -> Result<(), Error> {
let stream = self.stream()?;
debug!(target: LOG_TARGET_FILE, "sending request: {}", message);
stream.write_all(message.as_bytes())?;
stream.write_all(b"\n")?;
stream.flush()?;
Ok(())
}
fn send_message_get_job_template(&mut self) -> Result<(), Error> {
let params = types::worker_identifier::WorkerIdentifier {
id: self.last_request_id.clone(),
};
let req = types::rpc_request::RpcRequest {
id: Some(self.last_request_id.clone()),
jsonrpc: "2.0".to_string(),
method: "getjob".to_string(),
params: Some(serde_json::to_value(params)?),
};
let req_str = serde_json::to_string(&req)?;
self.send_message(&req_str)
}
fn send_login(&mut self) -> Result<(), Error> {
// only send the login request if a login string is configured
let login_str = match self.server_login.clone() {
None => "".to_string(),
Some(server_login) => server_login,
};
if login_str.is_empty() {
return Ok(());
}
let password_str = match self.server_password.clone() {
None => "".to_string(),
Some(server_password) => server_password,
};
let params = types::login_params::LoginParams {
login: login_str,
pass: password_str,
agent: "minotari-miner".to_string(),
};
let req_id = self.last_request_id.to_string();
let req = types::rpc_request::RpcRequest {
id: if req_id.is_empty() {
Some("0".to_string())
} else {
Some(req_id)
},
jsonrpc: "2.0".to_string(),
method: "login".to_string(),
params: Some(serde_json::to_value(params)?),
};
let req_str = serde_json::to_string(&req)?;
self.send_message(&req_str)
}
fn send_keepalive(&mut self) -> Result<(), Error> {
let req = types::rpc_request::RpcRequest {
id: Some(self.last_request_id.to_string()),
jsonrpc: "2.0".to_string(),
method: "keepalive".to_string(),
params: None,
};
let req_str = serde_json::to_string(&req)?;
self.send_message(&req_str)
}
fn send_message_submit(&mut self, job_id: u64, hash: String, nonce: u64) -> Result<(), Error> {
debug!(
target: LOG_TARGET,
"Submitting share with hash {} and nonce {}", hash, nonce
);
let params_in = types::submit_params::SubmitParams {
id: self.last_request_id.to_string(),
job_id,
hash,
nonce,
};
let params = serde_json::to_string(&params_in)?;
let req = types::rpc_request::RpcRequest {
id: Some(self.last_request_id.to_string()),
jsonrpc: "2.0".to_string(),
method: "submit".to_string(),
params: Some(serde_json::from_str(&params)?),
};
let req_str = serde_json::to_string(&req)?;
self.send_message(&req_str)
}
fn send_miner_job(&mut self, job: types::job_params::JobParams) -> Result<(), Error> {
let blob_bytes =
base64::decode(&job.blob).map_err(|_| Error::General("Invalid base64 byte string received".to_string()))?;
let miner_message = types::miner_message::MinerMessage::ReceivedJob(
job.height,
job.job_id.parse::<u64>()?,
job.target.parse::<u64>()?,
blob_bytes,
);
self.miner_tx.send(miner_message).map_err(Error::from)
}
fn send_miner_stop(&mut self) -> Result<(), Error> {
let miner_message = types::miner_message::MinerMessage::StopJob;
self.miner_tx.send(miner_message).map_err(Error::from)
}
fn send_miner_resume(&mut self) -> Result<(), Error> {
let miner_message = types::miner_message::MinerMessage::ResumeJob;
self.miner_tx.send(miner_message).map_err(Error::from)
}
pub fn handle_request(&mut self, req: types::rpc_request::RpcRequest) -> Result<(), Error> {
debug!(target: LOG_TARGET_FILE, "Received request type: {}", req.method);
match req.method.as_str() {
"job" => match req.params {
None => Err(Error::Request("No params in job request".to_owned())),
Some(params) => {
let job = serde_json::from_value::<types::job_params::JobParams>(params)?;
info!(
target: LOG_TARGET,
"Got a new job for height {} with target difficulty {}", job.height, job.target
);
self.send_miner_job(job)
},
},
_ => Err(Error::Request("Unknown method".to_owned())),
}
}
fn handle_error(&mut self, error: types::rpc_error::RpcError) {
if [-1, 24].contains(&error.code) {
// unauthorized
let _result = self.send_login();
} else if [21, 20, 22, 23, 25].contains(&error.code) {
// problem with template
let _result = self.send_message_get_job_template();
} else {
// unhandled
}
}
#[allow(clippy::cognitive_complexity)]
pub fn handle_response(&mut self, res: types::rpc_response::RpcResponse) -> Result<(), Error> {
debug!(target: LOG_TARGET_FILE, "Received response with id: {}", res.id);
match res.result {
Some(result) => {
let login_response = serde_json::from_value::<types::login_response::LoginResponse>(result.clone());
if let Ok(st) = login_response {
info!(
target: LOG_TARGET,
"Successful login to server, worker identifier is {}", st.id
);
info!(
target: LOG_TARGET,
"Got a new job for height {} with target difficulty {}", st.job.height, st.job.target
);
self.last_request_id = st.id;
let _result = self.send_miner_job(st.job);
return Ok(());
};
let job_response = serde_json::from_value::<types::job_params::JobParams>(result.clone());
if let Ok(st) = job_response {
info!(
target: LOG_TARGET,
"Got a new job for height {} with target difficulty {}", st.height, st.target
);
let _result = self.send_miner_job(st);
return Ok(());
};
let submit_response = serde_json::from_value::<types::submit_response::SubmitResponse>(result.clone());
if let Ok(st) = submit_response {
let error = st.error;
if let Some(error) = error {
// rejected share
self.handle_error(error);
warn!(target: LOG_TARGET, "Rejected");
} else {
// accepted share
debug!(target: LOG_TARGET, "Share accepted: {:?}", st.status);
}
return Ok(());
}
let rpc_response = serde_json::from_value::<types::rpc_response::RpcResponse>(result);
if let Ok(st) = rpc_response {
let error = st.error;
if let Some(error) = error {
self.handle_error(error);
}
return Ok(());
} else {
debug!(target: LOG_TARGET_FILE, "RPC Response: {:?}", rpc_response);
};
},
None => {
error!(target: LOG_TARGET, "RPC error: {:?}", res);
},
}
Ok(())
}
#[allow(clippy::cognitive_complexity)]
pub fn run(mut self) {
let server_read_interval = Duration::from_secs(1);
let server_retry_interval = Duration::from_secs(5);
let mut next_server_read = Instant::now() + server_read_interval;
let mut next_server_retry = Instant::now();
// Request the first job template
thread::sleep(Duration::from_secs(1));
let mut was_disconnected = true;
loop {
// Check our connection status, and try to correct if possible
if self.stream.is_none() {
if !was_disconnected {
let _result = self.send_miner_stop();
}
was_disconnected = true;
if Instant::now() > next_server_retry {
if self.try_connect().is_err() {
let status = format!(
"Connection Status: Can't establish server connection to {}. Will retry every {} seconds",
self.server_url,
server_retry_interval.as_secs()
);
warn!("{}", status);
self.stream = None;
} else {
let status = format!("Connection Status: Connected to server at {}.", self.server_url);
info!(target: LOG_TARGET, "{}", status);
}
next_server_retry = Instant::now() + server_retry_interval;
if self.stream.is_none() {
thread::sleep(std::time::Duration::from_secs(1));
continue;
}
}
} else {
// get new job template
if was_disconnected {
was_disconnected = false;
let _result = self.send_login();
let _result = self.send_miner_resume();
}
// read messages from server
if Instant::now() > next_server_read {
match self.read_message() {
Ok(Some(m)) => {
// figure out what kind of message,
// and dispatch appropriately
debug!(target: LOG_TARGET_FILE, "Received message: {}", m);
// Deserialize to see what type of object it is
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&m) {
// Is this a response or request?
if v["method"] == "job" {
// this is a request
match serde_json::from_str::<types::rpc_request::RpcRequest>(&m) {
Err(e) => error!(target: LOG_TARGET, "Error parsing request {} : {:?}", m, e),
Ok(request) => {
if let Err(err) = self.handle_request(request) {
error!(target: LOG_TARGET, "Error handling request {} : :{:?}", m, err)
}
},
}
} else {
// this is a response
match serde_json::from_str::<types::rpc_response::RpcResponse>(&m) {
Err(e) => error!(target: LOG_TARGET, "Error parsing response {} : {:?}", m, e),
Ok(response) => {
if let Err(err) = self.handle_response(response) {
error!(target: LOG_TARGET, "Error handling response {} : :{:?}", m, err)
}
},
}
}
continue;
} else {
error!(target: LOG_TARGET, "Error parsing message: {}", m)
}
},
Ok(None) => {
// noop, nothing to read for this interval
},
Err(e) => {
error!(target: LOG_TARGET, "Error reading message: {:?}", e);
self.stream = None;
continue;
},
}
next_server_read = Instant::now() + server_read_interval;
}
}
// Talk to the miner algorithm
while let Some(message) = self.rx.try_iter().next() {
debug!(target: LOG_TARGET_FILE, "Client received message: {:?}", message);
let result = match message {
types::client_message::ClientMessage::FoundSolution(job_id, hash, nonce) => {
self.send_message_submit(job_id, hash, nonce)
},
types::client_message::ClientMessage::KeepAlive => self.send_keepalive(),
types::client_message::ClientMessage::Shutdown => {
debug!(target: LOG_TARGET_FILE, "Shutting down client controller");
return;
},
};
if let Err(e) = result {
error!(target: LOG_TARGET, "Mining Controller Error {:?}", e);
self.stream = None;
}
}
thread::sleep(Duration::from_millis(10));
} // loop
}
}

View File

@ -0,0 +1,76 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use tari_max_size::MaxSizeBytesError;
use thiserror::Error;
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Error)]
pub enum Error {
#[error("Connection error: {0}")]
Connection(String),
#[error("Request error: {0}")]
Request(String),
// ResponseError(String),
#[error("Failed to parse JSON: {0}")]
Json(#[from] serde_json::error::Error),
#[error("Blob is not a valid hex value: {0}")]
Hex(#[from] hex::FromHexError),
#[error("System time error: {0}")]
Time(#[from] std::time::SystemTimeError),
#[error("Client Tx is not set")]
ClientTxNotSet,
#[error("Io error: {0}")]
Io(#[from] std::io::Error),
#[error("Can't create TLS connector: {0}")]
Tls(#[from] native_tls::Error),
#[error("Can't establish TLS connection: {0}")]
Tcp(#[from] Box<native_tls::HandshakeError<std::net::TcpStream>>),
#[error("No connected stream")]
NotConnected,
#[error("Can't parse int: {0}")]
Parse(#[from] std::num::ParseIntError),
#[error("General error: {0}")]
General(String),
#[error("Missing Data error: {0}")]
MissingData(String),
#[error("Limit exceeded error: {0}")]
MaxSizeBytesError(#[from] MaxSizeBytesError),
}
impl<T> From<std::sync::PoisonError<T>> for Error {
fn from(error: std::sync::PoisonError<T>) -> Self {
Error::General(format!("Failed to get lock: {:?}", error))
}
}
impl<T> From<std::sync::mpsc::SendError<T>> for Error {
fn from(error: std::sync::mpsc::SendError<T>) -> Self {
Error::General(format!("Failed to send to a channel: {:?}", error))
}
}
impl From<native_tls::HandshakeError<std::net::TcpStream>> for Error {
fn from(error: native_tls::HandshakeError<std::net::TcpStream>) -> Self {
Error::General(format!("TLS handshake error: {:?}", error))
}
}

View File

@ -0,0 +1,26 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pub mod controller;
pub mod error;
pub mod stratum_controller;
pub mod stratum_types;
pub mod stream;

View File

@ -0,0 +1,221 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::{convert::TryFrom, sync::mpsc, thread, time::SystemTime};
use borsh::BorshDeserialize;
use futures::stream::StreamExt;
use log::*;
use minotari_app_grpc::tari_rpc::BlockHeader;
//use tari_common_types::types::FixedHash;
use tari_max_size::MaxSizeBytes;
use tari_utilities::{hex::Hex, ByteArray};
use crate::{
miner::Miner,
run_miner::display_report,
stratum::{error::Error, stratum_types as types},
};
pub const LOG_TARGET: &str = "minotari::miner::stratum::controller";
pub const LOG_TARGET_FILE: &str = "minotari::logging::miner::stratum::controller";
type CurrentBlob = MaxSizeBytes<{ 4 * 1024 * 1024 }>; // 4 MiB
pub struct Controller {
rx: mpsc::Receiver<types::miner_message::MinerMessage>,
pub tx: mpsc::Sender<types::miner_message::MinerMessage>,
client_tx: Option<mpsc::Sender<types::client_message::ClientMessage>>,
current_height: u64,
current_job_id: u64,
current_difficulty_target: u64,
current_blob: CurrentBlob,
current_header: Option<BlockHeader>,
keep_alive_time: SystemTime,
num_mining_threads: usize,
}
impl Controller {
pub fn new(num_mining_threads: usize) -> Result<Controller, String> {
let (tx, rx) = mpsc::channel::<types::miner_message::MinerMessage>();
Ok(Controller {
rx,
tx,
client_tx: None,
current_height: 0,
current_job_id: 0,
current_difficulty_target: 0,
current_blob: CurrentBlob::default(),
current_header: None,
keep_alive_time: SystemTime::now(),
num_mining_threads,
})
}
pub fn set_client_tx(&mut self, client_tx: mpsc::Sender<types::client_message::ClientMessage>) {
self.client_tx = Some(client_tx);
}
#[allow(clippy::too_many_lines)]
pub async fn run(&mut self) -> Result<(), Error> {
let mut miner: Option<Miner> = None;
loop {
// lets see if we need to change the state of the miner.
while let Some(message) = self.rx.try_iter().next() {
debug!(target: LOG_TARGET_FILE, "Miner received message: {:?}", message);
match message {
types::miner_message::MinerMessage::ReceivedJob(height, job_id, diff, blob) => {
match self.should_we_update_job(height, job_id, diff, CurrentBlob::try_from(blob)?) {
Ok(should_we_update) => {
if should_we_update {
/*let header = self
.current_header
.clone()
.ok_or_else(|| Error::MissingData("Header".to_string()))?;
if let Some(acive_miner) = miner.as_mut() {
acive_miner.kill_threads();
}
miner = Some(Miner::init_mining(header, self.current_difficulty_target, self.num_mining_threads, true, FixedHash::zero(), None, ));*/
} else {
continue;
}
},
Err(e) => {
debug!(
target: LOG_TARGET_FILE,
"Miner could not decipher miner message: {:?}", e
);
// lets wait a second before we try again
thread::sleep(std::time::Duration::from_millis(1000));
continue;
},
}
},
types::miner_message::MinerMessage::StopJob => {
debug!(target: LOG_TARGET_FILE, "Stopping jobs");
miner = None;
continue;
},
types::miner_message::MinerMessage::ResumeJob => {
debug!(target: LOG_TARGET_FILE, "Resuming jobs");
miner = None;
continue;
},
types::miner_message::MinerMessage::Shutdown => {
debug!(
target: LOG_TARGET_FILE,
"Stopping jobs and Shutting down mining controller"
);
miner = None;
},
};
}
let mut submit = true;
if let Some(reporter) = miner.as_mut() {
if let Some(report) = (*reporter).next().await {
if let Some(header) = report.header.clone() {
if report.difficulty < self.current_difficulty_target {
submit = false;
debug!(
target: LOG_TARGET_FILE,
"Mined difficulty {} below target difficulty {}. Not submitting.",
report.difficulty,
self.current_difficulty_target
);
}
if submit {
// Mined a block fitting the difficulty
let block_header: tari_core::blocks::BlockHeader =
tari_core::blocks::BlockHeader::try_from(header).map_err(Error::MissingData)?;
let hash = block_header.hash().to_hex();
info!(
target: LOG_TARGET,
"Miner found share with hash {}, nonce {} and difficulty {:?}",
hash,
block_header.nonce,
report.difficulty
);
debug!(
target: LOG_TARGET_FILE,
"Miner found share with hash {}, difficulty {:?} and data {:?}",
hash,
report.difficulty,
block_header
);
self.client_tx
.as_mut()
.ok_or_else(|| Error::Connection("No connection to pool".to_string()))?
.send(types::client_message::ClientMessage::FoundSolution(
self.current_job_id,
hash,
block_header.nonce,
))?;
self.keep_alive_time = SystemTime::now();
continue;
} else {
display_report(&report, self.num_mining_threads).await;
}
} else {
display_report(&report, self.num_mining_threads).await;
}
}
}
if self.keep_alive_time.elapsed()?.as_secs() >= 30 {
self.keep_alive_time = SystemTime::now();
self.client_tx
.as_mut()
.ok_or(Error::ClientTxNotSet)?
.send(types::client_message::ClientMessage::KeepAlive)?;
}
}
}
pub fn should_we_update_job(
&mut self,
height: u64,
job_id: u64,
diff: u64,
blob: CurrentBlob,
) -> Result<bool, Error> {
if height != self.current_height ||
job_id != self.current_job_id ||
diff != self.current_difficulty_target ||
blob != self.current_blob
{
self.current_height = height;
self.current_job_id = job_id;
self.current_blob = blob.clone();
self.current_difficulty_target = diff;
let mut buffer = blob.as_bytes();
let tari_header: tari_core::blocks::BlockHeader = BorshDeserialize::deserialize(&mut buffer)
.map_err(|_| Error::General("Byte Blob is not a valid header".to_string()))?;
self.current_header = Some(minotari_app_grpc::tari_rpc::BlockHeader::from(tari_header));
Ok(true)
} else {
Ok(false)
}
}
}

View File

@ -0,0 +1,22 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pub(crate) mod controller;

View File

@ -0,0 +1,30 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub enum ClientMessage {
// job_id, hash, nonce
FoundSolution(u64, String, u64),
KeepAlive,
Shutdown,
}

View File

@ -0,0 +1,31 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
use tari_core::blocks::Block;
#[derive(Serialize, Deserialize, Debug)]
pub struct Job {
pub job_id: u64,
pub block: Option<Block>,
pub target: u64,
pub height: u64,
}

View File

@ -0,0 +1,30 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct JobParams {
pub job_id: String,
pub blob: String,
pub target: String,
pub height: u64,
}

View File

@ -0,0 +1,34 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use derivative::Derivative;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Derivative)]
#[derivative(Debug)]
pub struct LoginParams {
pub login: String,
#[derivative(Debug = "ignore")]
#[allow(dead_code)]
#[serde(skip_serializing)]
pub pass: String,
pub agent: String,
}

View File

@ -0,0 +1,30 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
use crate::stratum::stratum_types::job_params::JobParams;
#[derive(Serialize, Deserialize, Debug)]
pub struct LoginResponse {
pub id: String,
pub job: JobParams,
}

View File

@ -0,0 +1,31 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub enum MinerMessage {
// Height, Id, difficulty, HeaderBlob
ReceivedJob(u64, u64, u64, Vec<u8>),
ResumeJob,
StopJob,
Shutdown,
}

View File

@ -0,0 +1,33 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pub(crate) mod client_message;
pub(crate) mod job;
pub(crate) mod job_params;
pub(crate) mod login_params;
pub(crate) mod login_response;
pub(crate) mod miner_message;
pub(crate) mod rpc_error;
pub(crate) mod rpc_request;
pub(crate) mod rpc_response;
pub(crate) mod submit_params;
pub(crate) mod submit_response;
pub(crate) mod worker_identifier;

View File

@ -0,0 +1,28 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RpcError {
pub code: i32,
pub message: String,
}

View File

@ -0,0 +1,31 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize, Deserialize, Debug)]
pub struct RpcRequest {
pub id: Option<String>,
pub jsonrpc: String,
pub method: String,
pub params: Option<Value>,
}

View File

@ -0,0 +1,32 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::stratum::stratum_types::rpc_error::RpcError;
#[derive(Serialize, Deserialize, Debug)]
pub struct RpcResponse {
pub id: String,
pub result: Option<Value>,
pub error: Option<RpcError>,
}

View File

@ -0,0 +1,30 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct SubmitParams {
pub id: String,
pub job_id: u64,
pub nonce: u64,
pub hash: String,
}

View File

@ -0,0 +1,30 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
use crate::stratum::stratum_types::rpc_error::RpcError;
#[derive(Serialize, Deserialize, Debug)]
pub struct SubmitResponse {
pub status: Option<String>,
pub error: Option<RpcError>,
}

View File

@ -0,0 +1,27 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct WorkerIdentifier {
pub id: String,
}

View File

@ -0,0 +1,107 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::{
io::{self, BufRead, Read, Write},
net::TcpStream,
};
use bufstream::BufStream;
use native_tls::{TlsConnector, TlsStream};
use crate::stratum::error::Error;
pub(crate) enum Stream {
Stream(BufStream<TcpStream>),
TlsStream(Box<BufStream<TlsStream<TcpStream>>>),
}
impl Stream {
pub fn try_connect(server_url: &str, tls: Option<bool>) -> Result<Self, Error> {
let conn = TcpStream::connect(server_url)?;
if let Some(true) = tls {
let connector = TlsConnector::new()?;
let url_port: Vec<&str> = server_url.split(':').collect();
let split_url: Vec<&str> = url_port[0].split('.').collect();
let base_host = format!("{}.{}", split_url[split_url.len() - 2], split_url[split_url.len() - 1]);
let mut stream = connector.connect(&base_host, conn).map_err(Box::new)?;
stream.get_mut().set_nonblocking(true)?;
Ok(Self::TlsStream(Box::from(BufStream::new(stream))))
} else {
conn.set_nonblocking(true)?;
Ok(Self::Stream(BufStream::new(conn)))
}
}
fn reader(&mut self) -> &mut dyn Read {
match self {
Self::TlsStream(tls_stream) => tls_stream,
Self::Stream(stream) => stream,
}
}
fn writer(&mut self) -> &mut dyn Write {
match self {
Self::TlsStream(tls_stream) => tls_stream,
Self::Stream(stream) => stream,
}
}
fn buf_reader(&mut self) -> &mut dyn BufRead {
match self {
Self::TlsStream(tls_stream) => tls_stream,
Self::Stream(stream) => stream,
}
}
}
impl Write for Stream {
fn write(&mut self, b: &[u8]) -> Result<usize, io::Error> {
self.writer().write(b)
}
fn flush(&mut self) -> Result<(), io::Error> {
self.writer().flush()
}
}
impl Read for Stream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.reader().read(buf)
}
}
impl BufRead for Stream {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.buf_reader().fill_buf()
}
fn consume(&mut self, amt: usize) {
self.buf_reader().consume(amt)
}
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
self.buf_reader().read_until(byte, buf)
}
fn read_line(&mut self, string: &mut String) -> io::Result<usize> {
self.buf_reader().read_line(string)
}
}

View File

@ -0,0 +1,56 @@
@echo off
title Minotari Miner
rem Verify arguments
if ["%base_path%"]==[""] (
echo Problem with "base_path" environment variable: '%base_path%'
pause
exit /b 10101
)
if not exist "%base_path%" (
echo Path as per "base_path" environment variable not found: '%base_path%'
pause
exit /b 10101
)
if ["%my_exe%"]==[""] (
echo Problem with "my_exe" environment variable: '%my_exe%'
pause
exit /b 10101
)
rem Find the miner executable
if exist "%my_exe_path%\%my_exe%" (
set miner=%my_exe_path%\%my_exe%
echo.
echo Using "%my_exe%" found in %my_exe_path%
echo.
) else (
if exist "%base_path%\%my_exe%" (
set miner=%base_path%\%my_exe%
echo.
echo Using "%my_exe%" found in base_path
echo.
) else (
set FOUND=
for %%X in (%my_exe%) do (set FOUND=%%~$PATH:X)
if defined FOUND (
set miner=%my_exe%
echo.
echo Using "%my_exe%" found in system path:
where "%my_exe%"
echo.
) else (
echo.
echo Runtime "%my_exe%" not found in %my_exe_path%, base_path or the system path
echo.
pause
exit /b 10101
)
)
)
echo.
echo.
cd "%base_path%"
"%miner%" --base-path "%base_path%"

View File

@ -0,0 +1,28 @@
@echo off
echo.
echo Set up environment variables
echo ----------------------------
rem These are the miner executable and SQLite dynamic link library names
set my_exe=minotari_miner.exe
rem The default location for the miner executable
set my_exe_path=%~dp0
if %my_exe_path:~-1%==\ set my_exe_path=%my_exe_path:~0,-1%
echo my_exe_path = %my_exe_path%
rem The base folder where the database and log files will be located
set base_path=%~dp0..
echo base_path = %base_path%
echo.
echo Run the miner
echo ----------------------
call "%my_exe_path%\source_miner_env.bat"
goto END:
:END
echo.
pause

File diff suppressed because it is too large Load Diff

View File

@ -1,600 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "types.proto";
import "transaction.proto";
import "block.proto";
import "network.proto";
import "sidechain_types.proto";
package tari.rpc;
// The gRPC interface for interacting with the base node.
service BaseNode {
// Lists headers in the current best chain
rpc ListHeaders(ListHeadersRequest) returns (stream BlockHeaderResponse);
// Get header by hash
rpc GetHeaderByHash(GetHeaderByHashRequest) returns (BlockHeaderResponse);
// Returns blocks in the current best chain. Currently only supports querying by height
rpc GetBlocks(GetBlocksRequest) returns (stream HistoricalBlock);
// Returns the block timing for the chain heights
rpc GetBlockTiming(HeightRequest) returns (BlockTimingResponse);
// Returns the network Constants
rpc GetConstants(BlockHeight) returns (ConsensusConstants);
// Returns Block Sizes
rpc GetBlockSize (BlockGroupRequest) returns (BlockGroupResponse);
// Returns Block Fees
rpc GetBlockFees (BlockGroupRequest) returns (BlockGroupResponse);
// Get Version
rpc GetVersion(Empty) returns (StringValue);
// Check for new updates
rpc CheckForUpdates(Empty) returns (SoftwareUpdate);
// Get coins in circulation
rpc GetTokensInCirculation(GetBlocksRequest) returns (stream ValueAtHeightResponse);
// Get network difficulties
rpc GetNetworkDifficulty(HeightRequest) returns (stream NetworkDifficultyResponse);
// Get the block template
rpc GetNewBlockTemplate(NewBlockTemplateRequest) returns (NewBlockTemplateResponse);
// Construct a new block from a provided template
rpc GetNewBlock(NewBlockTemplate) returns (GetNewBlockResult);
// Construct a new block from a provided template
rpc GetNewBlockWithCoinbases(GetNewBlockWithCoinbasesRequest) returns (GetNewBlockResult);
// Construct a new block from a provided template
rpc GetNewBlockTemplateWithCoinbases(GetNewBlockTemplateWithCoinbasesRequest) returns (GetNewBlockResult);
// Construct a new block and header blob from a provided template
rpc GetNewBlockBlob(NewBlockTemplate) returns (GetNewBlockBlobResult);
// Submit a new block for propagation
rpc SubmitBlock(Block) returns (SubmitBlockResponse);
// Submit a new mined block blob for propagation
rpc SubmitBlockBlob(BlockBlobRequest) returns (SubmitBlockResponse);
// Submit a transaction for propagation
rpc SubmitTransaction(SubmitTransactionRequest) returns (SubmitTransactionResponse);
// Get the base node sync information
rpc GetSyncInfo(Empty) returns (SyncInfoResponse);
// Get the base node sync information
rpc GetSyncProgress(Empty) returns (SyncProgressResponse);
// Get the base node tip information
rpc GetTipInfo(Empty) returns (TipInfoResponse);
// Search for blocks containing the specified kernels
rpc SearchKernels(SearchKernelsRequest) returns (stream HistoricalBlock);
// Search for blocks containing the specified commitments
rpc SearchUtxos(SearchUtxosRequest) returns (stream HistoricalBlock);
// Fetch any utxos that exist in the main chain
rpc FetchMatchingUtxos(FetchMatchingUtxosRequest) returns (stream FetchMatchingUtxosResponse);
// get all peers from the base node
rpc GetPeers(GetPeersRequest) returns (stream GetPeersResponse);
rpc GetMempoolTransactions(GetMempoolTransactionsRequest) returns (stream GetMempoolTransactionsResponse);
rpc TransactionState(TransactionStateRequest) returns (TransactionStateResponse);
// This returns the node's network identity
rpc Identify (Empty) returns (NodeIdentity);
// Get Base Node network connectivity status
rpc GetNetworkStatus(Empty) returns (NetworkStatusResponse);
// List currently connected peers
rpc ListConnectedPeers(Empty) returns (ListConnectedPeersResponse);
// Get mempool stats
rpc GetMempoolStats(Empty) returns (MempoolStatsResponse);
// Get VNs
rpc GetActiveValidatorNodes(GetActiveValidatorNodesRequest) returns (stream GetActiveValidatorNodesResponse);
rpc GetShardKey(GetShardKeyRequest) returns (GetShardKeyResponse);
// Get templates
rpc GetTemplateRegistrations(GetTemplateRegistrationsRequest) returns (stream GetTemplateRegistrationResponse);
rpc GetSideChainUtxos(GetSideChainUtxosRequest) returns (stream GetSideChainUtxosResponse);
rpc GetNetworkState(GetNetworkStateRequest) returns (GetNetworkStateResponse);
// PayRef (Payment Reference) lookup for block explorers and external services
rpc SearchPaymentReferences(SearchPaymentReferencesRequest) returns (stream PaymentReferenceResponse);
}
message GetAssetMetadataRequest {
bytes asset_public_key = 1;
}
message GetAssetMetadataResponse {
string name = 2;
string description =3;
string image = 4;
bytes owner_commitment = 5;
OutputFeatures features = 6;
uint64 mined_height = 7;
bytes mined_in_block = 8;
}
message ListAssetRegistrationsRequest {
uint64 offset = 2;
uint64 count = 3;
}
message ListAssetRegistrationsResponse {
bytes asset_public_key = 1;
bytes unique_id = 2;
bytes owner_commitment = 3;
uint64 mined_height = 4;
bytes mined_in_block = 5;
OutputFeatures features = 6;
bytes script = 7;
}
message GetTokensRequest {
bytes asset_public_key = 1;
// Optionally get a set of specific unique_ids
repeated bytes unique_ids = 2;
}
message GetTokensResponse {
bytes unique_id = 1;
bytes asset_public_key = 2;
bytes owner_commitment = 3;
bytes mined_in_block = 4;
uint64 mined_height = 5;
OutputFeatures features = 6;
bytes script = 7;
}
message SubmitBlockResponse {
bytes block_hash = 1;
}
message BlockBlobRequest{
bytes header_blob = 1;
bytes body_blob = 2;
}
/// return type of GetTipInfo
message TipInfoResponse {
MetaData metadata = 1;
bool initial_sync_achieved = 2;
BaseNodeState base_node_state = 3;
bool failed_checkpoints = 4;
}
enum BaseNodeState{
START_UP = 0;
HEADER_SYNC = 1;
HORIZON_SYNC = 2;
CONNECTING = 3;
BLOCK_SYNC = 4;
LISTENING = 5;
SYNC_FAILED = 6;
}
/// return type of GetNewBlockTemplate
message NewBlockTemplateResponse {
NewBlockTemplate new_block_template = 1;
bool initial_sync_achieved = 3;
MinerData miner_data = 4;
}
/// return type of NewBlockTemplateRequest
message NewBlockTemplateRequest{
PowAlgo algo = 1;
//This field should be moved to optional once optional keyword is standard
uint64 max_weight = 2;
}
/// return type of NewBlockTemplateRequest
message GetNewBlockTemplateWithCoinbasesRequest{
PowAlgo algo = 1;
//This field should be moved to optional once optional keyword is standard
uint64 max_weight = 2;
repeated NewBlockCoinbase coinbases = 3;
}
/// request type of GetNewBlockWithCoinbasesRequest
message GetNewBlockWithCoinbasesRequest{
NewBlockTemplate new_template = 1;
repeated NewBlockCoinbase coinbases = 2;
}
message NewBlockCoinbase{
string address = 1;
uint64 value = 2;
bool stealth_payment= 3;
bool revealed_value_proof= 4;
bytes coinbase_extra =5;
}
// Network difficulty response
message NetworkDifficultyResponse {
uint64 difficulty = 1;
uint64 estimated_hash_rate = 2;
uint64 height = 3;
uint64 timestamp = 4;
uint64 pow_algo = 5;
uint64 sha3x_estimated_hash_rate = 6;
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
uint64 num_coinbases = 8;
repeated bytes coinbase_extras = 9;
}
// A generic single value response for a specific height
message ValueAtHeightResponse {
// uint64 circulating_supply = 1; // No longer used
// uint64 spendable_supply = 2; // No longer used
uint64 height = 3;
uint64 mined_rewards = 4;
uint64 spendable_rewards = 5;
uint64 spendable_pre_mine = 6;
uint64 total_spendable = 7;
}
// A generic uint value
message IntegerValue {
uint64 value = 1;
}
// A generic String value
message StringValue {
string value = 1;
}
/// GetBlockSize / GetBlockFees Request
/// Either the starting and ending heights OR the from_tip param must be specified
message BlockGroupRequest {
// The height from the chain tip (optional)
uint64 from_tip = 1;
// The starting height (optional)
uint64 start_height = 2;
// The ending height (optional)
uint64 end_height = 3;
/// The type of calculation required (optional)
/// Defaults to median
/// median, mean, quartile, quantile
CalcType calc_type = 4;
}
/// GetBlockSize / GetBlockFees Response
message BlockGroupResponse {
repeated double value = 1;
CalcType calc_type = 2;
}
enum CalcType {
MEAN = 0;
MEDIAN = 1;
QUANTILE = 2;
QUARTILE = 3;
}
// The request used for querying a function that requires a height, either between 2 points or from the chain tip
// If start_height and end_height are set and > 0, they take precedence, otherwise from_tip is used
message HeightRequest {
// The height from the chain tip (optional)
uint64 from_tip = 1;
// The starting height (optional)
uint64 start_height = 2;
// The ending height (optional)
uint64 end_height = 3;
}
// The return type of the rpc GetBlockTiming
message BlockTimingResponse {
uint64 max = 1;
uint64 min = 2;
double avg = 3;
}
// Request that returns a header based by hash
message GetHeaderByHashRequest {
// The hash of the block header
bytes hash = 1;
}
message BlockHeaderResponse {
// The block header
BlockHeader header = 1;
// The number of blocks from the tip of this block (a.k.a depth)
uint64 confirmations = 2;
// The block reward i.e mining reward + fees
uint64 reward = 3;
// Achieved difficulty
uint64 difficulty = 4;
// The number of transactions contained in the block
uint32 num_transactions = 5;
}
// The request used for querying headers from the base node. The parameters `from_height` and `num_headers` can be used
// to page through the current best chain.
message ListHeadersRequest {
// The height to start at. Depending on sorting, will either default to use the tip or genesis block, for `SORTING_DESC`
// and `SORTING_ASC` respectively, if a value is not provided. The first header returned will be at this height
// followed by `num_headers` - 1 headers in the direction specified by `sorting`. If greater than the current tip,
// the current tip will be used.
uint64 from_height = 1;
// The number of headers to return. If not specified, it will default to 10
uint64 num_headers = 2;
// The ordering to return the headers in. If not specified will default to SORTING_DESC. Note that if `from_height`
// is not specified or is 0, if `sorting` is SORTING_DESC, the tip will be used as `from_height`, otherwise the
// block at height 0 will be used.
Sorting sorting = 3;
}
// The request used for querying blocks in the base node's current best chain. Currently only querying by height is
// available. Multiple blocks may be queried.e.g. [189092,100023,122424]. The order in which they are returned is not
// guaranteed.
message GetBlocksRequest {
repeated uint64 heights = 1;
}
// The return type of the rpc GetBlocks. Blocks are not guaranteed to be returned in the order requested.
message GetBlocksResponse {
repeated HistoricalBlock blocks = 1;
}
enum Sorting {
SORTING_DESC = 0;
SORTING_ASC = 1;
}
message MetaData {
// The current chain height, or the block number of the longest valid chain, or `None` if there is no chain
uint64 best_block_height = 1;
// The block hash of the current tip of the longest valid chain, or `None` for an empty chain
bytes best_block_hash = 2;
// The current geometric mean of the pow of the chain tip, or `None` if there is no chain
bytes accumulated_difficulty = 5;
// This is the min height this node can provide complete blocks for. A 0 here means this node is archival and can provide complete blocks for every height.
uint64 pruned_height = 6;
uint64 timestamp = 7;
}
message SyncInfoResponse {
uint64 tip_height = 1;
uint64 local_height = 2;
repeated bytes peer_node_id = 3;
}
message SyncProgressResponse {
uint64 tip_height = 1;
uint64 local_height = 2;
SyncState state = 3;
string short_desc = 4;
uint64 initial_connected_peers = 5;
}
enum SyncState {
STARTUP = 0;
HEADER_STARTING = 1;
HEADER = 2;
BLOCK_STARTING = 3;
BLOCK = 4;
DONE = 5;
}
// This is the message that is returned for a miner after it asks for a new block.
message GetNewBlockResult{
// This is the header hash of the completed block
bytes block_hash = 1;
// This is the completed block
Block block = 2;
bytes merge_mining_hash =3;
bytes tari_unique_id =4;
MinerData miner_data = 5;
bytes vm_key = 6;
}
// This is the message that is returned for a miner after it asks for a new block.
message GetNewBlockBlobResult{
// This is the header hash of the completed block
bytes block_hash = 1;
// This is the completed block's header
bytes header = 2;
// This is the completed block's body
bytes block_body = 3;
bytes merge_mining_hash =4;
bytes utxo_mr = 5;
bytes tari_unique_id =6;
}
// This is mining data for the miner asking for a new block
message MinerData{
PowAlgo algo = 1;
uint64 target_difficulty = 2;
uint64 reward = 3;
// bytes merge_mining_hash =4;
uint64 total_fees = 5;
}
// This is the request type for the Search Kernels rpc
message SearchKernelsRequest{
repeated Signature signatures = 1;
}
// This is the request type for the Search Utxo rpc
message SearchUtxosRequest{
repeated bytes commitments = 1;
}
message FetchMatchingUtxosRequest {
repeated bytes hashes = 1;
}
message FetchMatchingUtxosResponse {
TransactionOutput output = 1;
}
// This is the request type of the get all peers rpc call
message GetPeersResponse{
Peer peer = 1;
}
message GetPeersRequest{}
message SubmitTransactionRequest {
Transaction transaction = 1;
}
message SubmitTransactionResponse {
SubmitTransactionResult result =1;
}
enum SubmitTransactionResult {
NONE = 0;
ACCEPTED = 1;
NOT_PROCESSABLE_AT_THIS_TIME = 2;
ALREADY_MINED = 3;
REJECTED = 4;
}
message GetMempoolTransactionsRequest {
}
message GetMempoolTransactionsResponse {
Transaction transaction = 1;
}
message TransactionStateRequest {
Signature excess_sig = 1;
}
message TransactionStateResponse {
TransactionLocation result =1;
}
enum TransactionLocation {
UNKNOWN = 0;
MEMPOOL = 1;
MINED = 2;
NOT_STORED = 3;
}
message MempoolStatsResponse {
uint64 unconfirmed_txs = 2;
uint64 reorg_txs = 3;
uint64 unconfirmed_weight = 4;
}
message GetActiveValidatorNodesRequest {
uint64 height = 1;
}
message GetActiveValidatorNodesResponse {
bytes shard_key = 1;
bytes public_key = 2;
}
message GetShardKeyRequest {
uint64 height = 1;
bytes public_key = 2;
}
message GetShardKeyResponse {
bytes shard_key = 1;
bool found = 2;
}
message GetTemplateRegistrationsRequest {
bytes start_hash = 1;
uint64 count = 2;
}
message GetTemplateRegistrationResponse {
bytes utxo_hash = 1;
TemplateRegistration registration = 2;
}
message BlockInfo {
uint64 height = 1;
bytes hash = 2;
bytes next_block_hash = 3;
}
message GetSideChainUtxosRequest {
bytes start_hash = 1;
uint64 count = 2;
}
message GetSideChainUtxosResponse {
BlockInfo block_info = 1;
repeated TransactionOutput outputs = 2;
}
message GetNetworkStateRequest {
}
message GetNetworkStateResponse {
// metadata
MetaData metadata = 1;
// has the base node synced
bool initial_sync_achieved = 2;
//current state of the base node
BaseNodeState base_node_state = 3;
// do we have failed checkpoints
bool failed_checkpoints = 4;
// The block reward of the next tip
uint64 reward = 5;
// estimate sha3x hash rate
uint64 sha3x_estimated_hash_rate = 6;
// estimate randomx hash rate
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
// number of connections
uint64 num_connections = 8;
//liveness results
repeated LivenessResult liveness_results = 9;
}
message LivenessResult{
// node id
bytes peer_node_id = 1;
// time to discover
uint64 discover_latency = 2;
// Dial latency
uint64 ping_latency = 3;
}
// PayRef (Payment Reference) search and lookup messages
// Request to search for outputs by payment reference
message SearchPaymentReferencesRequest {
// Payment reference as hex string (64 characters)
repeated string payment_reference_hex = 1;
repeated bytes payment_reference_bytes = 2;
// Optional: include spent outputs in results
bool include_spent = 3;
}
// Response containing payment reference match
message PaymentReferenceResponse {
// The payment reference that was found
string payment_reference_hex = 1;
// Block height where the output was mined
uint64 block_height = 2;
// Block hash where the output was mined
bytes block_hash = 3;
// Timestamp when the output was mined
uint64 mined_timestamp = 4;
// Output commitment (32 bytes)
bytes commitment = 5;
// Whether this output has been spent
bool is_spent = 6;
// Height where output was spent (if spent)
uint64 spent_height = 7;
// Block hash where output was spent (if spent)
bytes spent_block_hash = 8;
// Transaction output amount will be 0 for non set a
uint64 min_value_promise = 9;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,142 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "transaction.proto";
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
message BlockHeader {
// The hash of the block
bytes hash = 1;
// Version of the block
uint32 version = 2;
// Height of this block since the genesis block (height 0)
uint64 height = 3;
// Hash of the block previous to this in the chain.
bytes prev_hash = 4;
// Timestamp at which the block was built.
uint64 timestamp = 5;
// This is the UTXO merkle root of the outputs in the blockchain
bytes output_mr = 6;
// This is the merkle root of all outputs in this block
bytes block_output_mr = 7;
// This is the MMR root of the kernels
bytes kernel_mr = 8;
// This is the Merkle root of the inputs in this block
bytes input_mr = 9;
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
bytes total_kernel_offset = 10;
// Nonce increment used to mine this block.
uint64 nonce = 11;
// Proof of work metadata
ProofOfWork pow = 12;
// Kernel MMR size
uint64 kernel_mmr_size = 13;
// Output MMR size
uint64 output_mmr_size = 14;
// Sum of script offsets for all kernels in this block.
bytes total_script_offset = 15;
// Merkle root of validator nodes
bytes validator_node_mr = 16;
// Validator size
uint64 validator_node_size = 17;
}
// The proof of work data structure that is included in the block header.
message ProofOfWork {
// The algorithm used to mine this block
// 0 = Monero
// 1 = Sha3X
uint64 pow_algo = 1;
// Supplemental proof of work data. For example for Sha3x, this would be empty (only the block header is
// required), but for Monero merge mining we need the Monero block header and RandomX seed hash.
bytes pow_data = 4;
}
//This is used to request the which pow algo should be used with the block template
message PowAlgo {
// The permitted pow algorithms
enum PowAlgos {
POW_ALGOS_RANDOMXM = 0; // Accessible as `grpc::pow_algo::PowAlgos::RandomxM`
POW_ALGOS_SHA3X = 1; // Accessible as `grpc::pow_algo::PowAlgos::Sha3x`
POW_ALGOS_RANDOMXT = 2; // Accessible as `grpc::pow_algo::PowAlgos::RandomxT`
}
// The pow algo to use
PowAlgos pow_algo = 1;
}
// A Minotari block. Blocks are linked together into a blockchain.
message Block {
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
BlockHeader header = 1;
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// blocks consist of inputs, outputs and kernels, rather than transactions.
AggregateBody body = 2;
}
// The representation of a historical block in the blockchain. It is essentially identical to a protocol-defined
// block but contains some extra metadata that clients such as Block Explorers will find interesting.
message HistoricalBlock {
// The number of blocks that have been mined since this block, including this one. The current tip will have one
// confirmation.
uint64 confirmations = 1;
// The underlying block
Block block = 2;
}
// The NewBlockHeaderTemplate is used for the construction of a new mine-able block. It contains all the metadata for the block that the Base Node is able to complete on behalf of a Miner.
message NewBlockHeaderTemplate {
// Version of the block
uint32 version = 1;
// Height of this block since the genesis block (height 0)
uint64 height = 2;
// Hash of the block previous to this in the chain.
bytes prev_hash = 3;
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
bytes total_kernel_offset = 4;
// Proof of work metadata
ProofOfWork pow = 5;
// Sum of script offsets for all kernels in this block.
bytes total_script_offset = 7;
}
// The new block template is used constructing a new partial block, allowing a miner to added the coinbase utxo and as a final step the Base node to add the MMR roots to the header.
message NewBlockTemplate {
// The NewBlockHeaderTemplate is used for the construction of a new mineable block. It contains all the metadata for
// the block that the Base Node is able to complete on behalf of a Miner.
NewBlockHeaderTemplate header = 1;
// This flag indicates if the inputs, outputs and kernels have been sorted internally, that is, the sort() method
// has been called. This may be false even if all components are sorted.
AggregateBody body = 2;
// Sometimes the mempool has not synced to the latest tip, this flag indicates if the mempool is out of sync.
// In most cases the next call to get_new_block_template will return a block with the mempool in sync.
bool is_mempool_in_sync = 3;
}

View File

@ -1,783 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: block.proto
package block
import (
transaction "pool/internal/gbt/tari/proto/transaction"
reflect "reflect"
sync "sync"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// The permitted pow algorithms
type PowAlgo_PowAlgos int32
const (
PowAlgo_POW_ALGOS_RANDOMXM PowAlgo_PowAlgos = 0 // Accessible as `grpc::pow_algo::PowAlgos::RandomxM`
PowAlgo_POW_ALGOS_SHA3X PowAlgo_PowAlgos = 1 // Accessible as `grpc::pow_algo::PowAlgos::Sha3x`
PowAlgo_POW_ALGOS_RANDOMXT PowAlgo_PowAlgos = 2 // Accessible as `grpc::pow_algo::PowAlgos::RandomxT`
)
// Enum value maps for PowAlgo_PowAlgos.
var (
PowAlgo_PowAlgos_name = map[int32]string{
0: "POW_ALGOS_RANDOMXM",
1: "POW_ALGOS_SHA3X",
2: "POW_ALGOS_RANDOMXT",
}
PowAlgo_PowAlgos_value = map[string]int32{
"POW_ALGOS_RANDOMXM": 0,
"POW_ALGOS_SHA3X": 1,
"POW_ALGOS_RANDOMXT": 2,
}
)
func (x PowAlgo_PowAlgos) Enum() *PowAlgo_PowAlgos {
p := new(PowAlgo_PowAlgos)
*p = x
return p
}
func (x PowAlgo_PowAlgos) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (PowAlgo_PowAlgos) Descriptor() protoreflect.EnumDescriptor {
return file_block_proto_enumTypes[0].Descriptor()
}
func (PowAlgo_PowAlgos) Type() protoreflect.EnumType {
return &file_block_proto_enumTypes[0]
}
func (x PowAlgo_PowAlgos) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use PowAlgo_PowAlgos.Descriptor instead.
func (PowAlgo_PowAlgos) EnumDescriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{2, 0}
}
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
type BlockHeader struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The hash of the block
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
// Version of the block
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
// Height of this block since the genesis block (height 0)
Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
// Hash of the block previous to this in the chain.
PrevHash []byte `protobuf:"bytes,4,opt,name=prev_hash,json=prevHash,proto3" json:"prev_hash,omitempty"`
// Timestamp at which the block was built.
Timestamp uint64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// This is the UTXO merkle root of the outputs in the blockchain
OutputMr []byte `protobuf:"bytes,6,opt,name=output_mr,json=outputMr,proto3" json:"output_mr,omitempty"`
// This is the merkle root of all outputs in this block
BlockOutputMr []byte `protobuf:"bytes,7,opt,name=block_output_mr,json=blockOutputMr,proto3" json:"block_output_mr,omitempty"`
// This is the MMR root of the kernels
KernelMr []byte `protobuf:"bytes,8,opt,name=kernel_mr,json=kernelMr,proto3" json:"kernel_mr,omitempty"`
// This is the Merkle root of the inputs in this block
InputMr []byte `protobuf:"bytes,9,opt,name=input_mr,json=inputMr,proto3" json:"input_mr,omitempty"`
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
TotalKernelOffset []byte `protobuf:"bytes,10,opt,name=total_kernel_offset,json=totalKernelOffset,proto3" json:"total_kernel_offset,omitempty"`
// Nonce increment used to mine this block.
Nonce uint64 `protobuf:"varint,11,opt,name=nonce,proto3" json:"nonce,omitempty"`
// Proof of work metadata
Pow *ProofOfWork `protobuf:"bytes,12,opt,name=pow,proto3" json:"pow,omitempty"`
// Kernel MMR size
KernelMmrSize uint64 `protobuf:"varint,13,opt,name=kernel_mmr_size,json=kernelMmrSize,proto3" json:"kernel_mmr_size,omitempty"`
// Output MMR size
OutputMmrSize uint64 `protobuf:"varint,14,opt,name=output_mmr_size,json=outputMmrSize,proto3" json:"output_mmr_size,omitempty"`
// Sum of script offsets for all kernels in this block.
TotalScriptOffset []byte `protobuf:"bytes,15,opt,name=total_script_offset,json=totalScriptOffset,proto3" json:"total_script_offset,omitempty"`
// Merkle root of validator nodes
ValidatorNodeMr []byte `protobuf:"bytes,16,opt,name=validator_node_mr,json=validatorNodeMr,proto3" json:"validator_node_mr,omitempty"`
// Validator size
ValidatorNodeSize uint64 `protobuf:"varint,17,opt,name=validator_node_size,json=validatorNodeSize,proto3" json:"validator_node_size,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BlockHeader) Reset() {
*x = BlockHeader{}
mi := &file_block_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BlockHeader) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BlockHeader) ProtoMessage() {}
func (x *BlockHeader) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BlockHeader.ProtoReflect.Descriptor instead.
func (*BlockHeader) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{0}
}
func (x *BlockHeader) GetHash() []byte {
if x != nil {
return x.Hash
}
return nil
}
func (x *BlockHeader) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *BlockHeader) GetHeight() uint64 {
if x != nil {
return x.Height
}
return 0
}
func (x *BlockHeader) GetPrevHash() []byte {
if x != nil {
return x.PrevHash
}
return nil
}
func (x *BlockHeader) GetTimestamp() uint64 {
if x != nil {
return x.Timestamp
}
return 0
}
func (x *BlockHeader) GetOutputMr() []byte {
if x != nil {
return x.OutputMr
}
return nil
}
func (x *BlockHeader) GetBlockOutputMr() []byte {
if x != nil {
return x.BlockOutputMr
}
return nil
}
func (x *BlockHeader) GetKernelMr() []byte {
if x != nil {
return x.KernelMr
}
return nil
}
func (x *BlockHeader) GetInputMr() []byte {
if x != nil {
return x.InputMr
}
return nil
}
func (x *BlockHeader) GetTotalKernelOffset() []byte {
if x != nil {
return x.TotalKernelOffset
}
return nil
}
func (x *BlockHeader) GetNonce() uint64 {
if x != nil {
return x.Nonce
}
return 0
}
func (x *BlockHeader) GetPow() *ProofOfWork {
if x != nil {
return x.Pow
}
return nil
}
func (x *BlockHeader) GetKernelMmrSize() uint64 {
if x != nil {
return x.KernelMmrSize
}
return 0
}
func (x *BlockHeader) GetOutputMmrSize() uint64 {
if x != nil {
return x.OutputMmrSize
}
return 0
}
func (x *BlockHeader) GetTotalScriptOffset() []byte {
if x != nil {
return x.TotalScriptOffset
}
return nil
}
func (x *BlockHeader) GetValidatorNodeMr() []byte {
if x != nil {
return x.ValidatorNodeMr
}
return nil
}
func (x *BlockHeader) GetValidatorNodeSize() uint64 {
if x != nil {
return x.ValidatorNodeSize
}
return 0
}
// The proof of work data structure that is included in the block header.
type ProofOfWork struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The algorithm used to mine this block
//
// 0 = Monero
// 1 = Sha3X
PowAlgo uint64 `protobuf:"varint,1,opt,name=pow_algo,json=powAlgo,proto3" json:"pow_algo,omitempty"`
// Supplemental proof of work data. For example for Sha3x, this would be empty (only the block header is
// required), but for Monero merge mining we need the Monero block header and RandomX seed hash.
PowData []byte `protobuf:"bytes,4,opt,name=pow_data,json=powData,proto3" json:"pow_data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProofOfWork) Reset() {
*x = ProofOfWork{}
mi := &file_block_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProofOfWork) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProofOfWork) ProtoMessage() {}
func (x *ProofOfWork) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProofOfWork.ProtoReflect.Descriptor instead.
func (*ProofOfWork) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{1}
}
func (x *ProofOfWork) GetPowAlgo() uint64 {
if x != nil {
return x.PowAlgo
}
return 0
}
func (x *ProofOfWork) GetPowData() []byte {
if x != nil {
return x.PowData
}
return nil
}
// This is used to request the which pow algo should be used with the block template
type PowAlgo struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The pow algo to use
PowAlgo PowAlgo_PowAlgos `protobuf:"varint,1,opt,name=pow_algo,json=powAlgo,proto3,enum=tari.rpc.PowAlgo_PowAlgos" json:"pow_algo,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PowAlgo) Reset() {
*x = PowAlgo{}
mi := &file_block_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PowAlgo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PowAlgo) ProtoMessage() {}
func (x *PowAlgo) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PowAlgo.ProtoReflect.Descriptor instead.
func (*PowAlgo) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{2}
}
func (x *PowAlgo) GetPowAlgo() PowAlgo_PowAlgos {
if x != nil {
return x.PowAlgo
}
return PowAlgo_POW_ALGOS_RANDOMXM
}
// A Minotari block. Blocks are linked together into a blockchain.
type Block struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
Header *BlockHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// blocks consist of inputs, outputs and kernels, rather than transactions.
Body *transaction.AggregateBody `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Block) Reset() {
*x = Block{}
mi := &file_block_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Block) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Block) ProtoMessage() {}
func (x *Block) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Block.ProtoReflect.Descriptor instead.
func (*Block) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{3}
}
func (x *Block) GetHeader() *BlockHeader {
if x != nil {
return x.Header
}
return nil
}
func (x *Block) GetBody() *transaction.AggregateBody {
if x != nil {
return x.Body
}
return nil
}
// The representation of a historical block in the blockchain. It is essentially identical to a protocol-defined
// block but contains some extra metadata that clients such as Block Explorers will find interesting.
type HistoricalBlock struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The number of blocks that have been mined since this block, including this one. The current tip will have one
// confirmation.
Confirmations uint64 `protobuf:"varint,1,opt,name=confirmations,proto3" json:"confirmations,omitempty"`
// The underlying block
Block *Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HistoricalBlock) Reset() {
*x = HistoricalBlock{}
mi := &file_block_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HistoricalBlock) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HistoricalBlock) ProtoMessage() {}
func (x *HistoricalBlock) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HistoricalBlock.ProtoReflect.Descriptor instead.
func (*HistoricalBlock) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{4}
}
func (x *HistoricalBlock) GetConfirmations() uint64 {
if x != nil {
return x.Confirmations
}
return 0
}
func (x *HistoricalBlock) GetBlock() *Block {
if x != nil {
return x.Block
}
return nil
}
// The NewBlockHeaderTemplate is used for the construction of a new mine-able block. It contains all the metadata for the block that the Base Node is able to complete on behalf of a Miner.
type NewBlockHeaderTemplate struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Version of the block
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
// Height of this block since the genesis block (height 0)
Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
// Hash of the block previous to this in the chain.
PrevHash []byte `protobuf:"bytes,3,opt,name=prev_hash,json=prevHash,proto3" json:"prev_hash,omitempty"`
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
TotalKernelOffset []byte `protobuf:"bytes,4,opt,name=total_kernel_offset,json=totalKernelOffset,proto3" json:"total_kernel_offset,omitempty"`
// Proof of work metadata
Pow *ProofOfWork `protobuf:"bytes,5,opt,name=pow,proto3" json:"pow,omitempty"`
// Sum of script offsets for all kernels in this block.
TotalScriptOffset []byte `protobuf:"bytes,7,opt,name=total_script_offset,json=totalScriptOffset,proto3" json:"total_script_offset,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBlockHeaderTemplate) Reset() {
*x = NewBlockHeaderTemplate{}
mi := &file_block_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBlockHeaderTemplate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBlockHeaderTemplate) ProtoMessage() {}
func (x *NewBlockHeaderTemplate) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBlockHeaderTemplate.ProtoReflect.Descriptor instead.
func (*NewBlockHeaderTemplate) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{5}
}
func (x *NewBlockHeaderTemplate) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *NewBlockHeaderTemplate) GetHeight() uint64 {
if x != nil {
return x.Height
}
return 0
}
func (x *NewBlockHeaderTemplate) GetPrevHash() []byte {
if x != nil {
return x.PrevHash
}
return nil
}
func (x *NewBlockHeaderTemplate) GetTotalKernelOffset() []byte {
if x != nil {
return x.TotalKernelOffset
}
return nil
}
func (x *NewBlockHeaderTemplate) GetPow() *ProofOfWork {
if x != nil {
return x.Pow
}
return nil
}
func (x *NewBlockHeaderTemplate) GetTotalScriptOffset() []byte {
if x != nil {
return x.TotalScriptOffset
}
return nil
}
// The new block template is used constructing a new partial block, allowing a miner to added the coinbase utxo and as a final step the Base node to add the MMR roots to the header.
type NewBlockTemplate struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The NewBlockHeaderTemplate is used for the construction of a new mineable block. It contains all the metadata for
// the block that the Base Node is able to complete on behalf of a Miner.
Header *NewBlockHeaderTemplate `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// This flag indicates if the inputs, outputs and kernels have been sorted internally, that is, the sort() method
// has been called. This may be false even if all components are sorted.
Body *transaction.AggregateBody `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
// Sometimes the mempool has not synced to the latest tip, this flag indicates if the mempool is out of sync.
// In most cases the next call to get_new_block_template will return a block with the mempool in sync.
IsMempoolInSync bool `protobuf:"varint,3,opt,name=is_mempool_in_sync,json=isMempoolInSync,proto3" json:"is_mempool_in_sync,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBlockTemplate) Reset() {
*x = NewBlockTemplate{}
mi := &file_block_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBlockTemplate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBlockTemplate) ProtoMessage() {}
func (x *NewBlockTemplate) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBlockTemplate.ProtoReflect.Descriptor instead.
func (*NewBlockTemplate) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{6}
}
func (x *NewBlockTemplate) GetHeader() *NewBlockHeaderTemplate {
if x != nil {
return x.Header
}
return nil
}
func (x *NewBlockTemplate) GetBody() *transaction.AggregateBody {
if x != nil {
return x.Body
}
return nil
}
func (x *NewBlockTemplate) GetIsMempoolInSync() bool {
if x != nil {
return x.IsMempoolInSync
}
return false
}
var File_block_proto protoreflect.FileDescriptor
const file_block_proto_rawDesc = "" +
"\n" +
"\vblock.proto\x12\btari.rpc\x1a\x11transaction.proto\"\xd6\x04\n" +
"\vBlockHeader\x12\x12\n" +
"\x04hash\x18\x01 \x01(\fR\x04hash\x12\x18\n" +
"\aversion\x18\x02 \x01(\rR\aversion\x12\x16\n" +
"\x06height\x18\x03 \x01(\x04R\x06height\x12\x1b\n" +
"\tprev_hash\x18\x04 \x01(\fR\bprevHash\x12\x1c\n" +
"\ttimestamp\x18\x05 \x01(\x04R\ttimestamp\x12\x1b\n" +
"\toutput_mr\x18\x06 \x01(\fR\boutputMr\x12&\n" +
"\x0fblock_output_mr\x18\a \x01(\fR\rblockOutputMr\x12\x1b\n" +
"\tkernel_mr\x18\b \x01(\fR\bkernelMr\x12\x19\n" +
"\binput_mr\x18\t \x01(\fR\ainputMr\x12.\n" +
"\x13total_kernel_offset\x18\n" +
" \x01(\fR\x11totalKernelOffset\x12\x14\n" +
"\x05nonce\x18\v \x01(\x04R\x05nonce\x12'\n" +
"\x03pow\x18\f \x01(\v2\x15.tari.rpc.ProofOfWorkR\x03pow\x12&\n" +
"\x0fkernel_mmr_size\x18\r \x01(\x04R\rkernelMmrSize\x12&\n" +
"\x0foutput_mmr_size\x18\x0e \x01(\x04R\routputMmrSize\x12.\n" +
"\x13total_script_offset\x18\x0f \x01(\fR\x11totalScriptOffset\x12*\n" +
"\x11validator_node_mr\x18\x10 \x01(\fR\x0fvalidatorNodeMr\x12.\n" +
"\x13validator_node_size\x18\x11 \x01(\x04R\x11validatorNodeSize\"C\n" +
"\vProofOfWork\x12\x19\n" +
"\bpow_algo\x18\x01 \x01(\x04R\apowAlgo\x12\x19\n" +
"\bpow_data\x18\x04 \x01(\fR\apowData\"\x91\x01\n" +
"\aPowAlgo\x125\n" +
"\bpow_algo\x18\x01 \x01(\x0e2\x1a.tari.rpc.PowAlgo.PowAlgosR\apowAlgo\"O\n" +
"\bPowAlgos\x12\x16\n" +
"\x12POW_ALGOS_RANDOMXM\x10\x00\x12\x13\n" +
"\x0fPOW_ALGOS_SHA3X\x10\x01\x12\x16\n" +
"\x12POW_ALGOS_RANDOMXT\x10\x02\"c\n" +
"\x05Block\x12-\n" +
"\x06header\x18\x01 \x01(\v2\x15.tari.rpc.BlockHeaderR\x06header\x12+\n" +
"\x04body\x18\x02 \x01(\v2\x17.tari.rpc.AggregateBodyR\x04body\"^\n" +
"\x0fHistoricalBlock\x12$\n" +
"\rconfirmations\x18\x01 \x01(\x04R\rconfirmations\x12%\n" +
"\x05block\x18\x02 \x01(\v2\x0f.tari.rpc.BlockR\x05block\"\xf0\x01\n" +
"\x16NewBlockHeaderTemplate\x12\x18\n" +
"\aversion\x18\x01 \x01(\rR\aversion\x12\x16\n" +
"\x06height\x18\x02 \x01(\x04R\x06height\x12\x1b\n" +
"\tprev_hash\x18\x03 \x01(\fR\bprevHash\x12.\n" +
"\x13total_kernel_offset\x18\x04 \x01(\fR\x11totalKernelOffset\x12'\n" +
"\x03pow\x18\x05 \x01(\v2\x15.tari.rpc.ProofOfWorkR\x03pow\x12.\n" +
"\x13total_script_offset\x18\a \x01(\fR\x11totalScriptOffset\"\xa6\x01\n" +
"\x10NewBlockTemplate\x128\n" +
"\x06header\x18\x01 \x01(\v2 .tari.rpc.NewBlockHeaderTemplateR\x06header\x12+\n" +
"\x04body\x18\x02 \x01(\v2\x17.tari.rpc.AggregateBodyR\x04body\x12+\n" +
"\x12is_mempool_in_sync\x18\x03 \x01(\bR\x0fisMempoolInSyncB$Z\"pool/internal/gbt/tari/block;blockb\x06proto3"
var (
file_block_proto_rawDescOnce sync.Once
file_block_proto_rawDescData []byte
)
func file_block_proto_rawDescGZIP() []byte {
file_block_proto_rawDescOnce.Do(func() {
file_block_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_block_proto_rawDesc), len(file_block_proto_rawDesc)))
})
return file_block_proto_rawDescData
}
var file_block_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_block_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_block_proto_goTypes = []any{
(PowAlgo_PowAlgos)(0), // 0: tari.rpc.PowAlgo.PowAlgos
(*BlockHeader)(nil), // 1: tari.rpc.BlockHeader
(*ProofOfWork)(nil), // 2: tari.rpc.ProofOfWork
(*PowAlgo)(nil), // 3: tari.rpc.PowAlgo
(*Block)(nil), // 4: tari.rpc.Block
(*HistoricalBlock)(nil), // 5: tari.rpc.HistoricalBlock
(*NewBlockHeaderTemplate)(nil), // 6: tari.rpc.NewBlockHeaderTemplate
(*NewBlockTemplate)(nil), // 7: tari.rpc.NewBlockTemplate
(*transaction.AggregateBody)(nil), // 8: tari.rpc.AggregateBody
}
var file_block_proto_depIdxs = []int32{
2, // 0: tari.rpc.BlockHeader.pow:type_name -> tari.rpc.ProofOfWork
0, // 1: tari.rpc.PowAlgo.pow_algo:type_name -> tari.rpc.PowAlgo.PowAlgos
1, // 2: tari.rpc.Block.header:type_name -> tari.rpc.BlockHeader
8, // 3: tari.rpc.Block.body:type_name -> tari.rpc.AggregateBody
4, // 4: tari.rpc.HistoricalBlock.block:type_name -> tari.rpc.Block
2, // 5: tari.rpc.NewBlockHeaderTemplate.pow:type_name -> tari.rpc.ProofOfWork
6, // 6: tari.rpc.NewBlockTemplate.header:type_name -> tari.rpc.NewBlockHeaderTemplate
8, // 7: tari.rpc.NewBlockTemplate.body:type_name -> tari.rpc.AggregateBody
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_block_proto_init() }
func file_block_proto_init() {
if File_block_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_block_proto_rawDesc), len(file_block_proto_rawDesc)),
NumEnums: 1,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_block_proto_goTypes,
DependencyIndexes: file_block_proto_depIdxs,
EnumInfos: file_block_proto_enumTypes,
MessageInfos: file_block_proto_msgTypes,
}.Build()
File_block_proto = out.File
file_block_proto_goTypes = nil
file_block_proto_depIdxs = nil
}

View File

@ -1,790 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: network.proto
package net_work
import (
_ "github.com/golang/protobuf/ptypes/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ConnectivityStatus int32
const (
ConnectivityStatus_Initializing ConnectivityStatus = 0
ConnectivityStatus_Online ConnectivityStatus = 1
ConnectivityStatus_Degraded ConnectivityStatus = 2
ConnectivityStatus_Offline ConnectivityStatus = 3
)
// Enum value maps for ConnectivityStatus.
var (
ConnectivityStatus_name = map[int32]string{
0: "Initializing",
1: "Online",
2: "Degraded",
3: "Offline",
}
ConnectivityStatus_value = map[string]int32{
"Initializing": 0,
"Online": 1,
"Degraded": 2,
"Offline": 3,
}
)
func (x ConnectivityStatus) Enum() *ConnectivityStatus {
p := new(ConnectivityStatus)
*p = x
return p
}
func (x ConnectivityStatus) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ConnectivityStatus) Descriptor() protoreflect.EnumDescriptor {
return file_network_proto_enumTypes[0].Descriptor()
}
func (ConnectivityStatus) Type() protoreflect.EnumType {
return &file_network_proto_enumTypes[0]
}
func (x ConnectivityStatus) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ConnectivityStatus.Descriptor instead.
func (ConnectivityStatus) EnumDescriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{0}
}
type NodeIdentity struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
PublicAddresses []string `protobuf:"bytes,2,rep,name=public_addresses,json=publicAddresses,proto3" json:"public_addresses,omitempty"`
NodeId []byte `protobuf:"bytes,3,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeIdentity) Reset() {
*x = NodeIdentity{}
mi := &file_network_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeIdentity) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeIdentity) ProtoMessage() {}
func (x *NodeIdentity) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeIdentity.ProtoReflect.Descriptor instead.
func (*NodeIdentity) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{0}
}
func (x *NodeIdentity) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *NodeIdentity) GetPublicAddresses() []string {
if x != nil {
return x.PublicAddresses
}
return nil
}
func (x *NodeIdentity) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
type Peer struct {
state protoimpl.MessageState `protogen:"open.v1"`
// / Public key of the peer
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// / NodeId of the peer
NodeId []byte `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
// / Peer's addresses
Addresses []*Address `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"`
// / Last connection attempt to peer
LastConnection uint64 `protobuf:"varint,4,opt,name=last_connection,json=lastConnection,proto3" json:"last_connection,omitempty"`
// / Flags for the peer.
Flags uint32 `protobuf:"varint,5,opt,name=flags,proto3" json:"flags,omitempty"`
BannedUntil uint64 `protobuf:"varint,6,opt,name=banned_until,json=bannedUntil,proto3" json:"banned_until,omitempty"`
BannedReason string `protobuf:"bytes,7,opt,name=banned_reason,json=bannedReason,proto3" json:"banned_reason,omitempty"`
OfflineAt uint64 `protobuf:"varint,8,opt,name=offline_at,json=offlineAt,proto3" json:"offline_at,omitempty"`
// / Features supported by the peer
Features uint32 `protobuf:"varint,9,opt,name=features,proto3" json:"features,omitempty"`
// / used as information for more efficient protocol negotiation.
SupportedProtocols [][]byte `protobuf:"bytes,11,rep,name=supported_protocols,json=supportedProtocols,proto3" json:"supported_protocols,omitempty"`
// / User agent advertised by the peer
UserAgent string `protobuf:"bytes,12,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Peer) Reset() {
*x = Peer{}
mi := &file_network_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Peer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Peer) ProtoMessage() {}
func (x *Peer) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Peer.ProtoReflect.Descriptor instead.
func (*Peer) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{1}
}
func (x *Peer) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *Peer) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
func (x *Peer) GetAddresses() []*Address {
if x != nil {
return x.Addresses
}
return nil
}
func (x *Peer) GetLastConnection() uint64 {
if x != nil {
return x.LastConnection
}
return 0
}
func (x *Peer) GetFlags() uint32 {
if x != nil {
return x.Flags
}
return 0
}
func (x *Peer) GetBannedUntil() uint64 {
if x != nil {
return x.BannedUntil
}
return 0
}
func (x *Peer) GetBannedReason() string {
if x != nil {
return x.BannedReason
}
return ""
}
func (x *Peer) GetOfflineAt() uint64 {
if x != nil {
return x.OfflineAt
}
return 0
}
func (x *Peer) GetFeatures() uint32 {
if x != nil {
return x.Features
}
return 0
}
func (x *Peer) GetSupportedProtocols() [][]byte {
if x != nil {
return x.SupportedProtocols
}
return nil
}
func (x *Peer) GetUserAgent() string {
if x != nil {
return x.UserAgent
}
return ""
}
type NetworkStatusResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Status ConnectivityStatus `protobuf:"varint,1,opt,name=status,proto3,enum=tari.rpc.ConnectivityStatus" json:"status,omitempty"`
AvgLatencyMs uint32 `protobuf:"varint,2,opt,name=avg_latency_ms,json=avgLatencyMs,proto3" json:"avg_latency_ms,omitempty"`
NumNodeConnections uint32 `protobuf:"varint,3,opt,name=num_node_connections,json=numNodeConnections,proto3" json:"num_node_connections,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NetworkStatusResponse) Reset() {
*x = NetworkStatusResponse{}
mi := &file_network_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NetworkStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NetworkStatusResponse) ProtoMessage() {}
func (x *NetworkStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NetworkStatusResponse.ProtoReflect.Descriptor instead.
func (*NetworkStatusResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{2}
}
func (x *NetworkStatusResponse) GetStatus() ConnectivityStatus {
if x != nil {
return x.Status
}
return ConnectivityStatus_Initializing
}
func (x *NetworkStatusResponse) GetAvgLatencyMs() uint32 {
if x != nil {
return x.AvgLatencyMs
}
return 0
}
func (x *NetworkStatusResponse) GetNumNodeConnections() uint32 {
if x != nil {
return x.NumNodeConnections
}
return 0
}
type Address struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
LastSeen string `protobuf:"bytes,2,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"`
ConnectionAttempts uint32 `protobuf:"varint,3,opt,name=connection_attempts,json=connectionAttempts,proto3" json:"connection_attempts,omitempty"`
AvgLatency *AverageLatency `protobuf:"bytes,5,opt,name=avg_latency,json=avgLatency,proto3" json:"avg_latency,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Address) Reset() {
*x = Address{}
mi := &file_network_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Address) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Address) ProtoMessage() {}
func (x *Address) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Address.ProtoReflect.Descriptor instead.
func (*Address) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{3}
}
func (x *Address) GetAddress() []byte {
if x != nil {
return x.Address
}
return nil
}
func (x *Address) GetLastSeen() string {
if x != nil {
return x.LastSeen
}
return ""
}
func (x *Address) GetConnectionAttempts() uint32 {
if x != nil {
return x.ConnectionAttempts
}
return 0
}
func (x *Address) GetAvgLatency() *AverageLatency {
if x != nil {
return x.AvgLatency
}
return nil
}
type AverageLatency struct {
state protoimpl.MessageState `protogen:"open.v1"`
Latency uint64 `protobuf:"varint,1,opt,name=latency,proto3" json:"latency,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AverageLatency) Reset() {
*x = AverageLatency{}
mi := &file_network_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AverageLatency) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AverageLatency) ProtoMessage() {}
func (x *AverageLatency) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AverageLatency.ProtoReflect.Descriptor instead.
func (*AverageLatency) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{4}
}
func (x *AverageLatency) GetLatency() uint64 {
if x != nil {
return x.Latency
}
return 0
}
type ListConnectedPeersResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
ConnectedPeers []*Peer `protobuf:"bytes,1,rep,name=connected_peers,json=connectedPeers,proto3" json:"connected_peers,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListConnectedPeersResponse) Reset() {
*x = ListConnectedPeersResponse{}
mi := &file_network_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListConnectedPeersResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListConnectedPeersResponse) ProtoMessage() {}
func (x *ListConnectedPeersResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListConnectedPeersResponse.ProtoReflect.Descriptor instead.
func (*ListConnectedPeersResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{5}
}
func (x *ListConnectedPeersResponse) GetConnectedPeers() []*Peer {
if x != nil {
return x.ConnectedPeers
}
return nil
}
type SoftwareUpdate struct {
state protoimpl.MessageState `protogen:"open.v1"`
HasUpdate bool `protobuf:"varint,1,opt,name=has_update,json=hasUpdate,proto3" json:"has_update,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Sha string `protobuf:"bytes,3,opt,name=sha,proto3" json:"sha,omitempty"`
DownloadUrl string `protobuf:"bytes,4,opt,name=download_url,json=downloadUrl,proto3" json:"download_url,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SoftwareUpdate) Reset() {
*x = SoftwareUpdate{}
mi := &file_network_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SoftwareUpdate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SoftwareUpdate) ProtoMessage() {}
func (x *SoftwareUpdate) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SoftwareUpdate.ProtoReflect.Descriptor instead.
func (*SoftwareUpdate) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{6}
}
func (x *SoftwareUpdate) GetHasUpdate() bool {
if x != nil {
return x.HasUpdate
}
return false
}
func (x *SoftwareUpdate) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *SoftwareUpdate) GetSha() string {
if x != nil {
return x.Sha
}
return ""
}
func (x *SoftwareUpdate) GetDownloadUrl() string {
if x != nil {
return x.DownloadUrl
}
return ""
}
type GetIdentityRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetIdentityRequest) Reset() {
*x = GetIdentityRequest{}
mi := &file_network_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetIdentityRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetIdentityRequest) ProtoMessage() {}
func (x *GetIdentityRequest) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetIdentityRequest.ProtoReflect.Descriptor instead.
func (*GetIdentityRequest) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{7}
}
type GetIdentityResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
PublicAddress string `protobuf:"bytes,2,opt,name=public_address,json=publicAddress,proto3" json:"public_address,omitempty"`
NodeId []byte `protobuf:"bytes,3,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetIdentityResponse) Reset() {
*x = GetIdentityResponse{}
mi := &file_network_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetIdentityResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetIdentityResponse) ProtoMessage() {}
func (x *GetIdentityResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetIdentityResponse.ProtoReflect.Descriptor instead.
func (*GetIdentityResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{8}
}
func (x *GetIdentityResponse) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *GetIdentityResponse) GetPublicAddress() string {
if x != nil {
return x.PublicAddress
}
return ""
}
func (x *GetIdentityResponse) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
var File_network_proto protoreflect.FileDescriptor
const file_network_proto_rawDesc = "" +
"\n" +
"\rnetwork.proto\x12\btari.rpc\x1a\x1fgoogle/protobuf/timestamp.proto\"q\n" +
"\fNodeIdentity\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12)\n" +
"\x10public_addresses\x18\x02 \x03(\tR\x0fpublicAddresses\x12\x17\n" +
"\anode_id\x18\x03 \x01(\fR\x06nodeId\"\x81\x03\n" +
"\x04Peer\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12\x17\n" +
"\anode_id\x18\x02 \x01(\fR\x06nodeId\x12/\n" +
"\taddresses\x18\x03 \x03(\v2\x11.tari.rpc.AddressR\taddresses\x12'\n" +
"\x0flast_connection\x18\x04 \x01(\x04R\x0elastConnection\x12\x14\n" +
"\x05flags\x18\x05 \x01(\rR\x05flags\x12!\n" +
"\fbanned_until\x18\x06 \x01(\x04R\vbannedUntil\x12#\n" +
"\rbanned_reason\x18\a \x01(\tR\fbannedReason\x12\x1d\n" +
"\n" +
"offline_at\x18\b \x01(\x04R\tofflineAt\x12\x1a\n" +
"\bfeatures\x18\t \x01(\rR\bfeatures\x12/\n" +
"\x13supported_protocols\x18\v \x03(\fR\x12supportedProtocols\x12\x1d\n" +
"\n" +
"user_agent\x18\f \x01(\tR\tuserAgent\"\xa5\x01\n" +
"\x15NetworkStatusResponse\x124\n" +
"\x06status\x18\x01 \x01(\x0e2\x1c.tari.rpc.ConnectivityStatusR\x06status\x12$\n" +
"\x0eavg_latency_ms\x18\x02 \x01(\rR\favgLatencyMs\x120\n" +
"\x14num_node_connections\x18\x03 \x01(\rR\x12numNodeConnections\"\xac\x01\n" +
"\aAddress\x12\x18\n" +
"\aaddress\x18\x01 \x01(\fR\aaddress\x12\x1b\n" +
"\tlast_seen\x18\x02 \x01(\tR\blastSeen\x12/\n" +
"\x13connection_attempts\x18\x03 \x01(\rR\x12connectionAttempts\x129\n" +
"\vavg_latency\x18\x05 \x01(\v2\x18.tari.rpc.AverageLatencyR\n" +
"avgLatency\"*\n" +
"\x0eAverageLatency\x12\x18\n" +
"\alatency\x18\x01 \x01(\x04R\alatency\"U\n" +
"\x1aListConnectedPeersResponse\x127\n" +
"\x0fconnected_peers\x18\x01 \x03(\v2\x0e.tari.rpc.PeerR\x0econnectedPeers\"~\n" +
"\x0eSoftwareUpdate\x12\x1d\n" +
"\n" +
"has_update\x18\x01 \x01(\bR\thasUpdate\x12\x18\n" +
"\aversion\x18\x02 \x01(\tR\aversion\x12\x10\n" +
"\x03sha\x18\x03 \x01(\tR\x03sha\x12!\n" +
"\fdownload_url\x18\x04 \x01(\tR\vdownloadUrl\"\x14\n" +
"\x12GetIdentityRequest\"t\n" +
"\x13GetIdentityResponse\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12%\n" +
"\x0epublic_address\x18\x02 \x01(\tR\rpublicAddress\x12\x17\n" +
"\anode_id\x18\x03 \x01(\fR\x06nodeId*M\n" +
"\x12ConnectivityStatus\x12\x10\n" +
"\fInitializing\x10\x00\x12\n" +
"\n" +
"\x06Online\x10\x01\x12\f\n" +
"\bDegraded\x10\x02\x12\v\n" +
"\aOffline\x10\x03B*Z(pool/internal/gbt/tari/net_work;net_workb\x06proto3"
var (
file_network_proto_rawDescOnce sync.Once
file_network_proto_rawDescData []byte
)
func file_network_proto_rawDescGZIP() []byte {
file_network_proto_rawDescOnce.Do(func() {
file_network_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_network_proto_rawDesc), len(file_network_proto_rawDesc)))
})
return file_network_proto_rawDescData
}
var file_network_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_network_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_network_proto_goTypes = []any{
(ConnectivityStatus)(0), // 0: tari.rpc.ConnectivityStatus
(*NodeIdentity)(nil), // 1: tari.rpc.NodeIdentity
(*Peer)(nil), // 2: tari.rpc.Peer
(*NetworkStatusResponse)(nil), // 3: tari.rpc.NetworkStatusResponse
(*Address)(nil), // 4: tari.rpc.Address
(*AverageLatency)(nil), // 5: tari.rpc.AverageLatency
(*ListConnectedPeersResponse)(nil), // 6: tari.rpc.ListConnectedPeersResponse
(*SoftwareUpdate)(nil), // 7: tari.rpc.SoftwareUpdate
(*GetIdentityRequest)(nil), // 8: tari.rpc.GetIdentityRequest
(*GetIdentityResponse)(nil), // 9: tari.rpc.GetIdentityResponse
}
var file_network_proto_depIdxs = []int32{
4, // 0: tari.rpc.Peer.addresses:type_name -> tari.rpc.Address
0, // 1: tari.rpc.NetworkStatusResponse.status:type_name -> tari.rpc.ConnectivityStatus
5, // 2: tari.rpc.Address.avg_latency:type_name -> tari.rpc.AverageLatency
2, // 3: tari.rpc.ListConnectedPeersResponse.connected_peers:type_name -> tari.rpc.Peer
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_network_proto_init() }
func file_network_proto_init() {
if File_network_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_network_proto_rawDesc), len(file_network_proto_rawDesc)),
NumEnums: 1,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_network_proto_goTypes,
DependencyIndexes: file_network_proto_depIdxs,
EnumInfos: file_network_proto_enumTypes,
MessageInfos: file_network_proto_msgTypes,
}.Build()
File_network_proto = out.File
file_network_proto_goTypes = nil
file_network_proto_depIdxs = nil
}

View File

@ -1,97 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "google/protobuf/timestamp.proto";
message NodeIdentity {
bytes public_key = 1;
repeated string public_addresses = 2;
bytes node_id = 3;
}
message Peer {
/// Public key of the peer
bytes public_key =1;
/// NodeId of the peer
bytes node_id =2;
/// Peer's addresses
repeated Address addresses = 3;
/// Last connection attempt to peer
uint64 last_connection = 4;
/// Flags for the peer.
uint32 flags = 5;
uint64 banned_until= 6;
string banned_reason= 7;
uint64 offline_at = 8;
/// Features supported by the peer
uint32 features = 9;
/// used as information for more efficient protocol negotiation.
repeated bytes supported_protocols = 11;
/// User agent advertised by the peer
string user_agent = 12;
}
enum ConnectivityStatus {
Initializing = 0;
Online = 1;
Degraded = 2;
Offline = 3;
}
message NetworkStatusResponse {
ConnectivityStatus status = 1;
uint32 avg_latency_ms = 2;
uint32 num_node_connections = 3;
}
message Address{
bytes address =1;
string last_seen = 2;
uint32 connection_attempts = 3;
AverageLatency avg_latency = 5;
}
message AverageLatency {
uint64 latency = 1;
}
message ListConnectedPeersResponse {
repeated Peer connected_peers = 1;
}
message SoftwareUpdate {
bool has_update = 1;
string version = 2;
string sha = 3;
string download_url = 4;
}
message GetIdentityRequest { }
message GetIdentityResponse {
bytes public_key = 1;
string public_address = 2;
bytes node_id = 3;
}

View File

@ -1,61 +0,0 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "base_node.proto";
import "block.proto";
service ShaP2Pool {
rpc GetTipInfo(GetTipInfoRequest) returns(GetTipInfoResponse);
rpc GetNewBlock(GetNewBlockRequest) returns(GetNewBlockResponse);
rpc SubmitBlock(SubmitBlockRequest) returns(tari.rpc.SubmitBlockResponse);
}
message GetTipInfoRequest {
}
message GetTipInfoResponse {
uint64 node_height = 1;
bytes node_tip_hash = 2;
uint64 p2pool_rx_height = 3;
bytes p2pool_rx_tip_hash = 4;
uint64 p2pool_sha_height = 5;
bytes p2pool_sha_tip_hash = 6;
}
message GetNewBlockRequest {
tari.rpc.PowAlgo pow = 1;
string coinbase_extra = 2;
string wallet_payment_address = 3;
}
message GetNewBlockResponse {
tari.rpc.GetNewBlockResult block = 1;
uint64 target_difficulty = 2;
}
message SubmitBlockRequest {
tari.rpc.Block block = 1;
string wallet_payment_address = 2;
}

View File

@ -1,77 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "types.proto";
message SideChainFeature {
oneof side_chain_feature {
ValidatorNodeRegistration validator_node_registration = 1;
TemplateRegistration template_registration = 2;
ConfidentialOutputData confidential_output = 3;
}
}
message ValidatorNodeRegistration {
bytes public_key = 1;
Signature signature = 2;
}
message TemplateRegistration {
bytes author_public_key = 1;
Signature author_signature = 2;
string template_name = 3;
uint32 template_version = 4;
TemplateType template_type = 5;
BuildInfo build_info = 6;
bytes binary_sha = 7;
string binary_url = 8;
}
message ConfidentialOutputData {
bytes claim_public_key = 1;
}
message TemplateType {
oneof template_type {
WasmInfo wasm = 1;
FlowInfo flow = 2;
ManifestInfo manifest = 3;
}
}
message WasmInfo {
uint32 abi_version = 1;
}
message FlowInfo {
}
message ManifestInfo {
}
message BuildInfo {
string repo_url = 1;
bytes commit_hash = 2;
}

View File

@ -1,727 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: sidechain_types.proto
package sidechain_types
import (
types "pool/internal/gbt/tari/proto/types"
reflect "reflect"
sync "sync"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SideChainFeature struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to SideChainFeature:
//
// *SideChainFeature_ValidatorNodeRegistration
// *SideChainFeature_TemplateRegistration
// *SideChainFeature_ConfidentialOutput
SideChainFeature isSideChainFeature_SideChainFeature `protobuf_oneof:"side_chain_feature"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SideChainFeature) Reset() {
*x = SideChainFeature{}
mi := &file_sidechain_types_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SideChainFeature) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SideChainFeature) ProtoMessage() {}
func (x *SideChainFeature) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SideChainFeature.ProtoReflect.Descriptor instead.
func (*SideChainFeature) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{0}
}
func (x *SideChainFeature) GetSideChainFeature() isSideChainFeature_SideChainFeature {
if x != nil {
return x.SideChainFeature
}
return nil
}
func (x *SideChainFeature) GetValidatorNodeRegistration() *ValidatorNodeRegistration {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_ValidatorNodeRegistration); ok {
return x.ValidatorNodeRegistration
}
}
return nil
}
func (x *SideChainFeature) GetTemplateRegistration() *TemplateRegistration {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_TemplateRegistration); ok {
return x.TemplateRegistration
}
}
return nil
}
func (x *SideChainFeature) GetConfidentialOutput() *ConfidentialOutputData {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_ConfidentialOutput); ok {
return x.ConfidentialOutput
}
}
return nil
}
type isSideChainFeature_SideChainFeature interface {
isSideChainFeature_SideChainFeature()
}
type SideChainFeature_ValidatorNodeRegistration struct {
ValidatorNodeRegistration *ValidatorNodeRegistration `protobuf:"bytes,1,opt,name=validator_node_registration,json=validatorNodeRegistration,proto3,oneof"`
}
type SideChainFeature_TemplateRegistration struct {
TemplateRegistration *TemplateRegistration `protobuf:"bytes,2,opt,name=template_registration,json=templateRegistration,proto3,oneof"`
}
type SideChainFeature_ConfidentialOutput struct {
ConfidentialOutput *ConfidentialOutputData `protobuf:"bytes,3,opt,name=confidential_output,json=confidentialOutput,proto3,oneof"`
}
func (*SideChainFeature_ValidatorNodeRegistration) isSideChainFeature_SideChainFeature() {}
func (*SideChainFeature_TemplateRegistration) isSideChainFeature_SideChainFeature() {}
func (*SideChainFeature_ConfidentialOutput) isSideChainFeature_SideChainFeature() {}
type ValidatorNodeRegistration struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
Signature *types.Signature `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidatorNodeRegistration) Reset() {
*x = ValidatorNodeRegistration{}
mi := &file_sidechain_types_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidatorNodeRegistration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidatorNodeRegistration) ProtoMessage() {}
func (x *ValidatorNodeRegistration) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidatorNodeRegistration.ProtoReflect.Descriptor instead.
func (*ValidatorNodeRegistration) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{1}
}
func (x *ValidatorNodeRegistration) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *ValidatorNodeRegistration) GetSignature() *types.Signature {
if x != nil {
return x.Signature
}
return nil
}
type TemplateRegistration struct {
state protoimpl.MessageState `protogen:"open.v1"`
AuthorPublicKey []byte `protobuf:"bytes,1,opt,name=author_public_key,json=authorPublicKey,proto3" json:"author_public_key,omitempty"`
AuthorSignature *types.Signature `protobuf:"bytes,2,opt,name=author_signature,json=authorSignature,proto3" json:"author_signature,omitempty"`
TemplateName string `protobuf:"bytes,3,opt,name=template_name,json=templateName,proto3" json:"template_name,omitempty"`
TemplateVersion uint32 `protobuf:"varint,4,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"`
TemplateType *TemplateType `protobuf:"bytes,5,opt,name=template_type,json=templateType,proto3" json:"template_type,omitempty"`
BuildInfo *BuildInfo `protobuf:"bytes,6,opt,name=build_info,json=buildInfo,proto3" json:"build_info,omitempty"`
BinarySha []byte `protobuf:"bytes,7,opt,name=binary_sha,json=binarySha,proto3" json:"binary_sha,omitempty"`
BinaryUrl string `protobuf:"bytes,8,opt,name=binary_url,json=binaryUrl,proto3" json:"binary_url,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TemplateRegistration) Reset() {
*x = TemplateRegistration{}
mi := &file_sidechain_types_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TemplateRegistration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TemplateRegistration) ProtoMessage() {}
func (x *TemplateRegistration) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TemplateRegistration.ProtoReflect.Descriptor instead.
func (*TemplateRegistration) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{2}
}
func (x *TemplateRegistration) GetAuthorPublicKey() []byte {
if x != nil {
return x.AuthorPublicKey
}
return nil
}
func (x *TemplateRegistration) GetAuthorSignature() *types.Signature {
if x != nil {
return x.AuthorSignature
}
return nil
}
func (x *TemplateRegistration) GetTemplateName() string {
if x != nil {
return x.TemplateName
}
return ""
}
func (x *TemplateRegistration) GetTemplateVersion() uint32 {
if x != nil {
return x.TemplateVersion
}
return 0
}
func (x *TemplateRegistration) GetTemplateType() *TemplateType {
if x != nil {
return x.TemplateType
}
return nil
}
func (x *TemplateRegistration) GetBuildInfo() *BuildInfo {
if x != nil {
return x.BuildInfo
}
return nil
}
func (x *TemplateRegistration) GetBinarySha() []byte {
if x != nil {
return x.BinarySha
}
return nil
}
func (x *TemplateRegistration) GetBinaryUrl() string {
if x != nil {
return x.BinaryUrl
}
return ""
}
type ConfidentialOutputData struct {
state protoimpl.MessageState `protogen:"open.v1"`
ClaimPublicKey []byte `protobuf:"bytes,1,opt,name=claim_public_key,json=claimPublicKey,proto3" json:"claim_public_key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConfidentialOutputData) Reset() {
*x = ConfidentialOutputData{}
mi := &file_sidechain_types_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConfidentialOutputData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfidentialOutputData) ProtoMessage() {}
func (x *ConfidentialOutputData) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConfidentialOutputData.ProtoReflect.Descriptor instead.
func (*ConfidentialOutputData) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{3}
}
func (x *ConfidentialOutputData) GetClaimPublicKey() []byte {
if x != nil {
return x.ClaimPublicKey
}
return nil
}
type TemplateType struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to TemplateType:
//
// *TemplateType_Wasm
// *TemplateType_Flow
// *TemplateType_Manifest
TemplateType isTemplateType_TemplateType `protobuf_oneof:"template_type"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TemplateType) Reset() {
*x = TemplateType{}
mi := &file_sidechain_types_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TemplateType) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TemplateType) ProtoMessage() {}
func (x *TemplateType) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TemplateType.ProtoReflect.Descriptor instead.
func (*TemplateType) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{4}
}
func (x *TemplateType) GetTemplateType() isTemplateType_TemplateType {
if x != nil {
return x.TemplateType
}
return nil
}
func (x *TemplateType) GetWasm() *WasmInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Wasm); ok {
return x.Wasm
}
}
return nil
}
func (x *TemplateType) GetFlow() *FlowInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Flow); ok {
return x.Flow
}
}
return nil
}
func (x *TemplateType) GetManifest() *ManifestInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Manifest); ok {
return x.Manifest
}
}
return nil
}
type isTemplateType_TemplateType interface {
isTemplateType_TemplateType()
}
type TemplateType_Wasm struct {
Wasm *WasmInfo `protobuf:"bytes,1,opt,name=wasm,proto3,oneof"`
}
type TemplateType_Flow struct {
Flow *FlowInfo `protobuf:"bytes,2,opt,name=flow,proto3,oneof"`
}
type TemplateType_Manifest struct {
Manifest *ManifestInfo `protobuf:"bytes,3,opt,name=manifest,proto3,oneof"`
}
func (*TemplateType_Wasm) isTemplateType_TemplateType() {}
func (*TemplateType_Flow) isTemplateType_TemplateType() {}
func (*TemplateType_Manifest) isTemplateType_TemplateType() {}
type WasmInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
AbiVersion uint32 `protobuf:"varint,1,opt,name=abi_version,json=abiVersion,proto3" json:"abi_version,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WasmInfo) Reset() {
*x = WasmInfo{}
mi := &file_sidechain_types_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WasmInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WasmInfo) ProtoMessage() {}
func (x *WasmInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WasmInfo.ProtoReflect.Descriptor instead.
func (*WasmInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{5}
}
func (x *WasmInfo) GetAbiVersion() uint32 {
if x != nil {
return x.AbiVersion
}
return 0
}
type FlowInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FlowInfo) Reset() {
*x = FlowInfo{}
mi := &file_sidechain_types_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FlowInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FlowInfo) ProtoMessage() {}
func (x *FlowInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FlowInfo.ProtoReflect.Descriptor instead.
func (*FlowInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{6}
}
type ManifestInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ManifestInfo) Reset() {
*x = ManifestInfo{}
mi := &file_sidechain_types_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ManifestInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ManifestInfo) ProtoMessage() {}
func (x *ManifestInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ManifestInfo.ProtoReflect.Descriptor instead.
func (*ManifestInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{7}
}
type BuildInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
RepoUrl string `protobuf:"bytes,1,opt,name=repo_url,json=repoUrl,proto3" json:"repo_url,omitempty"`
CommitHash []byte `protobuf:"bytes,2,opt,name=commit_hash,json=commitHash,proto3" json:"commit_hash,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuildInfo) Reset() {
*x = BuildInfo{}
mi := &file_sidechain_types_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuildInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuildInfo) ProtoMessage() {}
func (x *BuildInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuildInfo.ProtoReflect.Descriptor instead.
func (*BuildInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{8}
}
func (x *BuildInfo) GetRepoUrl() string {
if x != nil {
return x.RepoUrl
}
return ""
}
func (x *BuildInfo) GetCommitHash() []byte {
if x != nil {
return x.CommitHash
}
return nil
}
var File_sidechain_types_proto protoreflect.FileDescriptor
const file_sidechain_types_proto_rawDesc = "" +
"\n" +
"\x15sidechain_types.proto\x12\btari.rpc\x1a\vtypes.proto\"\xbb\x02\n" +
"\x10SideChainFeature\x12e\n" +
"\x1bvalidator_node_registration\x18\x01 \x01(\v2#.tari.rpc.ValidatorNodeRegistrationH\x00R\x19validatorNodeRegistration\x12U\n" +
"\x15template_registration\x18\x02 \x01(\v2\x1e.tari.rpc.TemplateRegistrationH\x00R\x14templateRegistration\x12S\n" +
"\x13confidential_output\x18\x03 \x01(\v2 .tari.rpc.ConfidentialOutputDataH\x00R\x12confidentialOutputB\x14\n" +
"\x12side_chain_feature\"m\n" +
"\x19ValidatorNodeRegistration\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x121\n" +
"\tsignature\x18\x02 \x01(\v2\x13.tari.rpc.SignatureR\tsignature\"\x81\x03\n" +
"\x14TemplateRegistration\x12*\n" +
"\x11author_public_key\x18\x01 \x01(\fR\x0fauthorPublicKey\x12>\n" +
"\x10author_signature\x18\x02 \x01(\v2\x13.tari.rpc.SignatureR\x0fauthorSignature\x12#\n" +
"\rtemplate_name\x18\x03 \x01(\tR\ftemplateName\x12)\n" +
"\x10template_version\x18\x04 \x01(\rR\x0ftemplateVersion\x12;\n" +
"\rtemplate_type\x18\x05 \x01(\v2\x16.tari.rpc.TemplateTypeR\ftemplateType\x122\n" +
"\n" +
"build_info\x18\x06 \x01(\v2\x13.tari.rpc.BuildInfoR\tbuildInfo\x12\x1d\n" +
"\n" +
"binary_sha\x18\a \x01(\fR\tbinarySha\x12\x1d\n" +
"\n" +
"binary_url\x18\b \x01(\tR\tbinaryUrl\"B\n" +
"\x16ConfidentialOutputData\x12(\n" +
"\x10claim_public_key\x18\x01 \x01(\fR\x0eclaimPublicKey\"\xa9\x01\n" +
"\fTemplateType\x12(\n" +
"\x04wasm\x18\x01 \x01(\v2\x12.tari.rpc.WasmInfoH\x00R\x04wasm\x12(\n" +
"\x04flow\x18\x02 \x01(\v2\x12.tari.rpc.FlowInfoH\x00R\x04flow\x124\n" +
"\bmanifest\x18\x03 \x01(\v2\x16.tari.rpc.ManifestInfoH\x00R\bmanifestB\x0f\n" +
"\rtemplate_type\"+\n" +
"\bWasmInfo\x12\x1f\n" +
"\vabi_version\x18\x01 \x01(\rR\n" +
"abiVersion\"\n" +
"\n" +
"\bFlowInfo\"\x0e\n" +
"\fManifestInfo\"G\n" +
"\tBuildInfo\x12\x19\n" +
"\brepo_url\x18\x01 \x01(\tR\arepoUrl\x12\x1f\n" +
"\vcommit_hash\x18\x02 \x01(\fR\n" +
"commitHashB8Z6pool/internal/gbt/tari/sidechain_types;sidechain_typesb\x06proto3"
var (
file_sidechain_types_proto_rawDescOnce sync.Once
file_sidechain_types_proto_rawDescData []byte
)
func file_sidechain_types_proto_rawDescGZIP() []byte {
file_sidechain_types_proto_rawDescOnce.Do(func() {
file_sidechain_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_sidechain_types_proto_rawDesc), len(file_sidechain_types_proto_rawDesc)))
})
return file_sidechain_types_proto_rawDescData
}
var file_sidechain_types_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_sidechain_types_proto_goTypes = []any{
(*SideChainFeature)(nil), // 0: tari.rpc.SideChainFeature
(*ValidatorNodeRegistration)(nil), // 1: tari.rpc.ValidatorNodeRegistration
(*TemplateRegistration)(nil), // 2: tari.rpc.TemplateRegistration
(*ConfidentialOutputData)(nil), // 3: tari.rpc.ConfidentialOutputData
(*TemplateType)(nil), // 4: tari.rpc.TemplateType
(*WasmInfo)(nil), // 5: tari.rpc.WasmInfo
(*FlowInfo)(nil), // 6: tari.rpc.FlowInfo
(*ManifestInfo)(nil), // 7: tari.rpc.ManifestInfo
(*BuildInfo)(nil), // 8: tari.rpc.BuildInfo
(*types.Signature)(nil), // 9: tari.rpc.Signature
}
var file_sidechain_types_proto_depIdxs = []int32{
1, // 0: tari.rpc.SideChainFeature.validator_node_registration:type_name -> tari.rpc.ValidatorNodeRegistration
2, // 1: tari.rpc.SideChainFeature.template_registration:type_name -> tari.rpc.TemplateRegistration
3, // 2: tari.rpc.SideChainFeature.confidential_output:type_name -> tari.rpc.ConfidentialOutputData
9, // 3: tari.rpc.ValidatorNodeRegistration.signature:type_name -> tari.rpc.Signature
9, // 4: tari.rpc.TemplateRegistration.author_signature:type_name -> tari.rpc.Signature
4, // 5: tari.rpc.TemplateRegistration.template_type:type_name -> tari.rpc.TemplateType
8, // 6: tari.rpc.TemplateRegistration.build_info:type_name -> tari.rpc.BuildInfo
5, // 7: tari.rpc.TemplateType.wasm:type_name -> tari.rpc.WasmInfo
6, // 8: tari.rpc.TemplateType.flow:type_name -> tari.rpc.FlowInfo
7, // 9: tari.rpc.TemplateType.manifest:type_name -> tari.rpc.ManifestInfo
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_sidechain_types_proto_init() }
func file_sidechain_types_proto_init() {
if File_sidechain_types_proto != nil {
return
}
file_sidechain_types_proto_msgTypes[0].OneofWrappers = []any{
(*SideChainFeature_ValidatorNodeRegistration)(nil),
(*SideChainFeature_TemplateRegistration)(nil),
(*SideChainFeature_ConfidentialOutput)(nil),
}
file_sidechain_types_proto_msgTypes[4].OneofWrappers = []any{
(*TemplateType_Wasm)(nil),
(*TemplateType_Flow)(nil),
(*TemplateType_Manifest)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_sidechain_types_proto_rawDesc), len(file_sidechain_types_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_sidechain_types_proto_goTypes,
DependencyIndexes: file_sidechain_types_proto_depIdxs,
MessageInfos: file_sidechain_types_proto_msgTypes,
}.Build()
File_sidechain_types_proto = out.File
file_sidechain_types_proto_goTypes = nil
file_sidechain_types_proto_depIdxs = nil
}

View File

@ -1,188 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "types.proto";
import "sidechain_types.proto";
// The transaction kernel tracks the excess for a given transaction. For an explanation of what the excess is, and
// why it is necessary, refer to the
// [Mimblewimble TLU post](https://tlu.tarilabs.com/protocols/mimblewimble-1/sources/PITCHME.link.html?highlight=mimblewimble#mimblewimble).
// The kernel also tracks other transaction metadata, such as the lock height for the transaction (i.e. the earliest
// this transaction can be mined) and the transaction fee, in cleartext.
message TransactionKernel {
// Options for a kernel's structure or use
uint32 features = 1;
/// Fee originally included in the transaction this proof is for (in MicroMinotari)
uint64 fee = 2;
// This kernel is not valid earlier than lock_height blocks
// The max lock_height of all *inputs* to this transaction
uint64 lock_height = 3;
// Remainder of the sum of all transaction commitments. If the transaction
// is well formed, amounts components should sum to zero and the excess
// is hence a valid public key.
bytes excess = 6;
// The signature proving the excess is a valid public key, which signs
// the transaction fee.
Signature excess_sig = 7;
// The hash of the kernel, as it appears in the MMR
bytes hash = 8;
// Version
uint32 version = 9;
// Optional burned commitment
bytes burn_commitment = 10;
}
// A transaction input.
//
// Primarily a reference to an output being spent by the transaction.
message TransactionInput {
// The features of the output being spent. We will check maturity for all outputs.
OutputFeatures features = 1;
// The commitment referencing the output being spent.
bytes commitment = 2;
// Hash of the input, as it appears in the MMR
bytes hash = 3;
// The serialised script
bytes script = 4;
// The script input data, if any
bytes input_data = 5;
// A signature with k_s, signing the script, input data, and mined height
ComAndPubSignature script_signature = 7;
// The offset public key, K_O
bytes sender_offset_public_key = 8;
// The hash of the output this input is spending
bytes output_hash = 9;
// Covenant
bytes covenant = 10;
// Version
uint32 version = 11;
// The encrypted data
bytes encrypted_data = 12;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 13;
// The metadata signature for output this input is spending
ComAndPubSignature metadata_signature = 14;
// The rangeproof hash for output this input is spending
bytes rangeproof_hash = 15;
}
// Output for a transaction, defining the new ownership of coins that are being transferred. The commitment is a
// blinded value for the output while the range proof guarantees the commitment includes a positive value without
// overflow and the ownership of the private key.
message TransactionOutput {
// Options for an output's structure or use
OutputFeatures features = 1;
// The homomorphic commitment representing the output amount
bytes commitment = 2;
// A proof that the commitment is in the right range
RangeProof range_proof = 3;
// The hash of the output, as it appears in the MMR
bytes hash = 4;
// Tari script serialised script
bytes script = 5;
// Tari script offset public key, K_O
bytes sender_offset_public_key = 6;
// Metadata signature with the homomorphic commitment private values (amount and blinding factor) and the sender
// offset private key
ComAndPubSignature metadata_signature = 7;
// Covenant
bytes covenant = 8;
// Version
uint32 version = 9;
// Encrypted Pedersen commitment openings (value and mask) for the output
bytes encrypted_data = 10;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 11;
// Payment reference (PayRef) - 32-byte Blake2b hash of (block_hash || output_hash)
// This provides a unique, deterministic reference for the output that can be used
// for payment verification without revealing wallet ownership
bytes payment_reference = 12;
}
// Options for UTXOs
message OutputFeatures {
// Version
uint32 version = 1;
// The type of output, eg Coinbase, all of which have different consensus rules
uint32 output_type = 2;
// The maturity of the specific UTXO. This is the min lock height at which an UTXO can be spend. Coinbase UTXO
// require a min maturity of the Coinbase_lock_height, this should be checked on receiving new blocks.
uint64 maturity = 3;
// Additional arbitrary info in coinbase transactions supplied by miners
bytes coinbase_extra = 4;
// Features that are specific to a side chain
SideChainFeature sidechain_feature = 5;
// The type of range proof used in the output
uint32 range_proof_type = 6;
}
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// cut-through means that blocks and transactions have the same structure. The inputs, outputs and kernels should
// be sorted by their Blake2b-256bit digest hash
message AggregateBody {
// List of inputs spent by the transaction.
repeated TransactionInput inputs = 1;
// List of outputs the transaction produces.
repeated TransactionOutput outputs = 2;
// Kernels contain the excesses and their signatures for transaction
repeated TransactionKernel kernels = 3;
}
// A transaction which consists of a kernel offset and an aggregate body made up of inputs, outputs and kernels.
message Transaction {
bytes offset = 1;
AggregateBody body = 2;
bytes script_offset = 3;
}
message UnblindedOutput {
// Value of the output
uint64 value = 1;
// Spending key of the output
bytes spending_key = 2;
// Options for an output's structure or use
OutputFeatures features = 3;
// Tari script serialised script
bytes script = 4;
// Tari script input data for spending
bytes input_data = 5;
// Tari script private key
bytes script_private_key = 7;
// Tari script offset pubkey, K_O
bytes sender_offset_public_key = 8;
// UTXO signature with the script offset private key, k_O
ComAndPubSignature metadata_signature = 9;
// The minimum height the script allows this output to be spent
uint64 script_lock_height = 10;
// Covenant
bytes covenant = 11;
// Encrypted data
bytes encrypted_data = 12;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 13;
// The range proof
RangeProof range_proof = 14;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
/// An unsigned range interface to more accurately represent Rust native Range's
message Range {
uint64 min = 1;
uint64 max = 2;
}
/// An Empty placeholder for endpoints without request parameters
message Empty {}
/// Define an interface for block height
message BlockHeight {
uint64 block_height = 1;
}
// Define the explicit Signature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type.
message Signature {
bytes public_nonce = 1;
bytes signature = 2;
}
// Define the explicit ComAndPubSignature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type.
message ComAndPubSignature {
bytes ephemeral_commitment = 1;
bytes ephemeral_pubkey = 2;
bytes u_a = 3;
bytes u_x = 4;
bytes u_y = 5;
}
// Define the explicit CommitmentSignature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type
message CommitmentSignature {
bytes public_nonce = 1;
bytes u = 2;
bytes v = 3;
}
/// PoW Algorithm constants
message PowAlgorithmConstants {
uint64 min_difficulty = 2;
uint64 max_difficulty = 3;
uint64 target_time = 4;
}
/// Weight params
message WeightParams {
uint64 kernel_weight = 1;
uint64 input_weight = 2;
uint64 output_weight = 3;
uint64 features_and_scripts_bytes_per_gram = 4;
}
/// Output version
message OutputsVersion {
Range outputs = 1;
Range features = 2;
}
/// Output types
enum OutputType {
STANDARD = 0;
COINBASE = 1;
BURN = 2;
VALIDATOR_NODE_REGISTRATION = 3;
CODE_TEMPLATE_REGISTRATION = 4;
}
/// Range proof types
enum RangeProofType {
BULLETPROOF_PLUS = 0;
REVEALED_VALUE = 1;
}
message PermittedRangeProofs {
OutputType output_type = 1;
repeated RangeProofType range_proof_types = 2;
}
/// Range proof
message RangeProof {
bytes proof_bytes = 1;
}
/// Consensus Constants response
message ConsensusConstants {
uint64 coinbase_min_maturity = 1;
uint32 blockchain_version = 2;
uint64 future_time_limit = 3;
uint64 difficulty_block_window = 5;
uint64 max_block_transaction_weight = 7;
uint64 pow_algo_count = 8;
uint64 median_timestamp_count = 9;
uint64 emission_initial = 10;
repeated uint64 emission_decay = 11;
uint64 emission_tail = 12 [deprecated=true];
uint64 min_sha3x_pow_difficulty = 13;
uint64 block_weight_inputs = 14;
uint64 block_weight_outputs = 15;
uint64 block_weight_kernels = 16;
uint64 pre_mine_value = 17;
uint64 max_script_byte_size = 18;
uint64 validator_node_validity_period = 19;
uint64 effective_from_height = 20;
Range valid_blockchain_version_range = 21;
uint64 max_randomx_seed_height = 22;
map<uint32, PowAlgorithmConstants> proof_of_work = 23;
WeightParams transaction_weight = 24;
Range input_version_range = 26;
OutputsVersion output_version_range = 27;
Range kernel_version_range = 28;
repeated OutputType permitted_output_types = 29;
uint64 epoch_length = 30;
uint64 validator_node_registration_min_deposit_amount = 31;
uint64 validator_node_registration_min_lock_height = 32;
uint64 validator_node_registration_shuffle_interval_epoch = 33;
repeated PermittedRangeProofs permitted_range_proof_types = 34;
uint64 inflation_bips = 35;
uint64 tail_epoch_length = 36;
uint64 max_block_coinbase_count = 37;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,132 +0,0 @@
// Copyright 2021. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "types.proto";
import "network.proto";
import "transaction.proto";
package tari.rpc;
service ValidatorNode {
rpc GetIdentity(GetIdentityRequest) returns (GetIdentityResponse);
rpc GetMetadata(GetMetadataRequest) returns (GetMetadataResponse);
rpc GetTokenData(GetTokenDataRequest) returns (GetTokenDataResponse);
// rpc ExecuteInstruction(ExecuteInstructionRequest) returns (ExecuteInstructionResponse);
rpc InvokeReadMethod(InvokeReadMethodRequest) returns (InvokeReadMethodResponse);
rpc InvokeMethod(InvokeMethodRequest) returns (InvokeMethodResponse);
rpc GetConstitutionRequests(GetConstitutionRequestsRequest) returns (stream TransactionOutput);
rpc PublishContractAcceptance(PublishContractAcceptanceRequest) returns (PublishContractAcceptanceResponse);
rpc PublishContractUpdateProposalAcceptance(PublishContractUpdateProposalAcceptanceRequest) returns (PublishContractUpdateProposalAcceptanceResponse);
}
message GetConstitutionRequestsRequest {
// empty
}
message GetMetadataRequest {
// empty
}
message PublishContractAcceptanceRequest {
bytes contract_id = 1;
}
message PublishContractAcceptanceResponse {
string status = 1;
uint64 tx_id = 2;
}
message PublishContractUpdateProposalAcceptanceRequest {
bytes contract_id = 1;
uint64 proposal_id = 2;
}
message PublishContractUpdateProposalAcceptanceResponse {
string status = 1;
uint64 tx_id = 2;
}
message GetMetadataResponse {
repeated SidechainMetadata sidechains = 1;
}
message SidechainMetadata {
bytes asset_public_key =1;
uint64 committed_height = 2;
bytes committed_hash = 3;
}
message GetTokenDataRequest {
bytes asset_pub_key = 1;
bytes unique_id = 2;
}
message GetTokenDataResponse {
}
//message ExecuteInstructionRequest{
// bytes asset_public_key = 1;
// uint32 template_id = 2;
// string method = 3;
// bytes args = 4;
//// bytes token_id = 5;
//// bytes signature = 6;
//}
//
//message ExecuteInstructionResponse {
// string status = 1;
// optional bytes result = 2;
//}
message InvokeReadMethodRequest{
bytes contract_id = 1;
uint32 template_id = 2;
string method = 3;
bytes args = 4;
bytes sender = 5;
}
message InvokeReadMethodResponse {
bytes result = 1;
Authority authority = 2;
}
message Authority {
bytes node_public_key =1;
bytes signature = 2;
bytes proxied_by = 3;
}
message InvokeMethodRequest {
bytes contract_id = 1;
uint32 template_id = 2;
string method = 3;
bytes args = 4;
bytes sender = 5;
}
message InvokeMethodResponse {
string status = 1;
bytes result = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
package sha3x
import (
"context"
"crypto/rand"
"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"pool/internal/db"
"pool/internal/gbt/coin"
"pool/internal/gbt/dbif"
"pool/internal/gbt/tari"
"pool/internal/msg"
"pool/internal/utility"
"sync"
"sync/atomic"
"time"
"go.uber.org/zap"
)
const GBT_SHA3X_VERSION string = "sha3x v1.0"
type Sha3xAddrConfig struct {
Addr string `json:"addr"`
}
type Sha3xConfig struct {
Monero Sha3xAddrConfig `json:"sha3x"`
}
type GbtSha3xContext struct {
Config Sha3xConfig
GbtCtx *coin.GbtContext
Ctx context.Context
last_time time.Time
last_gbt tari.TariBlockTemplate
last_blockhash string
last_height uint64
Submits float64
addressIndex int
Target []byte
Header []byte
last_body string
Jobs sync.Map
JobIds []string
JobGenCount int
new_block_chan chan int
new_block_index int
}
var logg *zap.Logger
var GbtSha3xCtx GbtSha3xContext
func configInit(config *Sha3xConfig) {
data, err := ioutil.ReadFile("gbt.conf")
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {
GbtSha3xCtx.GbtCtx = GbtCtx
GbtSha3xCtx.last_height = 0
configInit(&GbtSha3xCtx.Config)
GbtSha3xCtx.JobGenCount = 0
GbtSha3xCtx.Target = make([]byte, 32)
GbtSha3xCtx.Header = make([]byte, 49)
GbtSha3xCtx.last_time = time.Now()
GbtSha3xCtx.Ctx = context.Background()
logg = GbtCtx.Log
GbtSha3xCtx.new_block_chan = make(chan int, 256)
GbtSha3xCtx.new_block_index = 0
logg.Info("[gbt]", zap.String("gbt_sha3x_version", GBT_SHA3X_VERSION))
}
func Start() {
go gbt_running(&GbtSha3xCtx)
go gbt_notify_running(&GbtSha3xCtx)
go submit_block_running(&GbtSha3xCtx)
}
func Stop() {
defer close(GbtSha3xCtx.new_block_chan)
}
func update_block_confirm(gbt *GbtSha3xContext) {
}
func randomxJobId() string {
// 生成4个字节
bytes := make([]byte, 4)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
// 转成 hex 字符串
hexStr := hex.EncodeToString(bytes)
return hexStr
}
func removeJobs(gbt *GbtSha3xContext, clean bool) {
if !clean {
if len(gbt.JobIds) > 10 {
end := len(gbt.JobIds) - 10
for i := 0; i < end; i++ {
gbt.Jobs.Delete(gbt.JobIds[i])
}
gbt.JobIds = gbt.JobIds[end:]
}
} else {
gbt.Jobs.Range(func(key, value interface{}) bool {
gbt.Jobs.Delete(key)
return true
})
gbt.JobIds = nil
gbt.JobGenCount = 0
}
}
func gbt_running(gbt *GbtSha3xContext) {
ticker := time.NewTicker(1000 * time.Millisecond)
defer ticker.Stop()
for gbt.GbtCtx.Started {
select {
case <-ticker.C:
// 获取区块模板
blockTemplate, err := gbt.GbtCtx.TariClient.GetBlockTemplate(gbt.Ctx, 1)
if err != nil || len(blockTemplate.Header) != 638 {
fmt.Println("任务模板中的区块头长度:", len(blockTemplate.Header))
return
}
// 初始化 ZMQ 发布通道
if gbt.GbtCtx.PubCh == nil {
gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
continue
}
height := blockTemplate.Height
if height == gbt.last_height {
removeJobs(gbt, false)
if gbt.JobGenCount >= 10 {
generateJob(gbt, &blockTemplate)
gbt.JobGenCount = 0 // 成功生成 Job 后重置计数器
}
} else {
removeJobs(gbt, true)
generateJob(gbt, &blockTemplate)
gbt.last_height = height
gbt.JobGenCount = 0 // 高度变化也重置计数器
}
// 标记存活
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
// 无论是否需要发布新任务,计数均+1保持至少10秒更新一次任务
gbt.JobGenCount += 1
case blkIdx := <-gbt.new_block_chan:
log.Println("new block chan", blkIdx)
update_block_confirm(gbt)
case <-gbt.GbtCtx.ExitGbtChan:
logg.Error("[gbt]", zap.String("gbt", "exit"))
return
}
}
}
func generateJob(gbt *GbtSha3xContext, blockTemplate *tari.TariBlockTemplate) {
for trycnt := 0; trycnt < 3; trycnt++ {
job := msg.Sha3xJob{
JobId: randomxJobId(),
MiningHash: blockTemplate.MiningHash,
Header: blockTemplate.Header,
Body: blockTemplate.Body,
TargetDifficulty: blockTemplate.TargetDifficulty,
Height: blockTemplate.Height,
}
sendMsg := msg.Sha3xStratumJob{
JobId: job.JobId,
Header: job.MiningHash,
U64target: job.TargetDifficulty,
Height: uint32(job.Height),
}
bt, err := json.Marshal(sendMsg)
if err != nil {
fmt.Println(err)
continue
}
// 保存 Job
gbt.Jobs.LoadOrStore(job.JobId, job)
gbt.JobIds = append(gbt.JobIds, job.JobId)
// 发布 Job
if err := gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobsha3x"), bt}); err != nil {
logg.Warn("[gbt]", zap.String("job", err.Error()))
continue
}
logg.Warn("[gbt]", zap.String("job", "sent"))
gbt.JobGenCount++
break
}
}
func gbt_notify_running(gbt *GbtSha3xContext) {
for {
if !gbt.GbtCtx.Started {
break
}
if gbt.GbtCtx.MoneroNewBlockSubCh == nil {
gbt.GbtCtx.MoneroNewBlockSubCh = utility.InitZmqSub(gbt.GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
}
if gbt.GbtCtx.MoneroNewBlockSubCh != nil {
cmsg_sub, err := gbt.GbtCtx.MoneroNewBlockSubCh.RecvMessage()
if err != nil {
if !gbt.GbtCtx.Started {
break
}
gbt.GbtCtx.MoneroNewBlockSubCh.SetSubscribe(utility.BITCOIND_ZMQ_HASHBLOCK)
gbt.GbtCtx.MoneroNewBlockSubCh.Connect(gbt.GbtCtx.Config.Rpc.ZmqSub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "hashblock" {
GbtSha3xCtx.new_block_index = GbtSha3xCtx.new_block_index + 1
//log.Println("gbt_notify_running", hex.EncodeToString(cmsg_sub[1]), GbtNexaCtx.new_block_index)
gbt.new_block_chan <- GbtSha3xCtx.new_block_index
}
}
} else {
logg.Error("[gbt]", zap.String("notify", "NodeSubCh fail!"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
type ServerSubmitBlock struct {
JobId string
Header []byte
Body []byte
Nonce string
}
func submit_block_running(block *GbtSha3xContext) {
logg.Info("[block]", zap.String("submit_block_running", "Start."))
for {
if !block.GbtCtx.Started {
break
}
if block.GbtCtx.SubCh == nil {
block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
}
if block.GbtCtx.SubCh != nil {
cmsg_sub, err := block.GbtCtx.SubCh.RecvMessage()
if err != nil {
if !block.GbtCtx.Started {
break
}
time.Sleep(time.Duration(1) * time.Second)
block.GbtCtx.SubCh.SetSubscribe("blk" + block.GbtCtx.Coin)
block.GbtCtx.SubCh.Connect(block.GbtCtx.Config.Zmq.Sub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "blksha3x" {
cmsg := cmsg_sub[1]
//block data
msgb := make([]byte, len(cmsg)-16)
copy(msgb, cmsg)
var submitMsg msg.BlockSha3xMsg
if err := json.Unmarshal(msgb, &submitMsg); err != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to Unmarshal job", err.Error()))
continue
}
var height = submitMsg.Height
logg.Warn("[block]", zap.Uint64("height", height))
if height <= block.last_height {
continue
}
block.last_height = height
indexb, err1 := hex.DecodeString(string(cmsg[len(msgb)+8:]))
if err1 != nil {
logg.Error("[block]", zap.String("failed to decode index", err1.Error()))
continue
}
var index uint32 = utility.ByteToUint32(indexb)
logg.Warn("[block]", zap.Uint32("index", index))
logg.Debug("[block]", zap.String("msg", string(cmsg)), zap.String("blk", string(msgb)))
if v, ok := block.Jobs.Load(submitMsg.Id); ok {
job := v.(*msg.Sha3xJob) // 类型断言
headerStr, bodyStr := job.Header, job.Body
header, err := hex.DecodeString(headerStr)
if err != nil {
fmt.Println(err)
return
}
body, err := hex.DecodeString(bodyStr)
if err != nil {
fmt.Println(err)
return
}
nonceByte := make([]byte, 8)
binary.LittleEndian.PutUint64(nonceByte, submitMsg.Nonce)
copy(header[311:319], nonceByte)
blockHash_byte, _ := block.GbtCtx.TariClient.SubmitBlock(block.Ctx, header, body)
nonceStr := fmt.Sprintf("%x", submitMsg.Nonce)
blockHash := hex.EncodeToString(blockHash_byte)
dbif.NotifyPoolBlkStatsSubmitResult(block.GbtCtx, int64(height), blockHash, "OK", nonceStr, submitMsg.SubIdx)
block.Submits += 1
logg.Warn("[block]", zap.Float64("total submits", block.Submits), zap.Int64("SubIdx", submitMsg.SubIdx))
new_block_into_db(block, submitMsg.User, submitMsg.Miner, submitMsg.Index, int64(height), nonceStr, blockHash, submitMsg.SubIdx)
}
}
}
} else {
logg.Error("[block]", zap.String("block", "SubCh failed! retry"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
func new_block_into_db(block *GbtSha3xContext, user string, miner string, minerid string, height int64, nonce string, hash string, subidx int64) bool {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
log.Printf("Error opening database: %v", err)
return false
}
defer db.Close()
createTableSQL := `
CREATE TABLE IF NOT EXISTS blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
miner TEXT NOT NULL,
minerid TEXT NOT NULL,
height INTEGER,
nonce TEXT NOT NULL,
hash TEXT NOT NULL,
subidx INTEGER,
checked INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Printf("Error creating table: %v", err)
return false
}
insertSQL := `INSERT INTO blocks (user, miner, minerid, height, nonce, checked, hash, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
_, err = db.Exec(insertSQL, user, miner, minerid, height, nonce, 0, hash, subidx)
if err != nil {
log.Printf("Error inserting data from blocks %s: %v", fmt.Sprint(height), err)
return false
}
return true
}

View File

@ -1,120 +0,0 @@
package tari
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
base_node "pool/internal/gbt/tari/proto"
block "pool/internal/gbt/tari/proto/block"
"google.golang.org/grpc"
)
// var PowAlgoMap = []string{"randomxM", "sha3x", "randomxT"}
type BaseNodeClient struct {
Conn *grpc.ClientConn
Client base_node.BaseNodeClient
}
// 创建BaseNode客户端
func NewBaseNodeClient(address string) (*BaseNodeClient, error) {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
return nil, fmt.Errorf("failed to connect to base node: %v", err)
}
// 移除 defer conn.Close(),让连接保持打开状态
client := base_node.NewBaseNodeClient(conn)
return &BaseNodeClient{
Conn: conn,
Client: client,
}, nil
}
// Close 关闭GRPC连接
func (c *BaseNodeClient) Close() error {
if c.Conn != nil {
return c.Conn.Close()
}
return nil
}
type TariBlockTemplate struct {
MiningHash string
Header string
Body string
Height uint64
TargetDifficulty uint64
}
func base64ToHex(data string) (string, error) {
result, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", err
}
return hex.EncodeToString(result), nil
}
func (nc *BaseNodeClient) GetBlockTemplate(ctx context.Context, powIndex uint32) (TariBlockTemplate, error) {
var pow_algo block.PowAlgo_PowAlgos
switch powIndex {
case 0:
pow_algo = block.PowAlgo_POW_ALGOS_RANDOMXM
case 1:
pow_algo = block.PowAlgo_POW_ALGOS_SHA3X
case 2:
pow_algo = block.PowAlgo_POW_ALGOS_RANDOMXT
default:
fmt.Println("不支持", powIndex, "算法")
}
templateReq := &base_node.NewBlockTemplateRequest{
Algo: &block.PowAlgo{
PowAlgo: pow_algo,
},
MaxWeight: 0x00,
}
templateResp, err := nc.Client.GetNewBlockTemplate(ctx, templateReq)
if err != nil {
fmt.Println(pow_algo, "获取区块模板失败:", err)
return TariBlockTemplate{}, err
}
// 节点未同步完成
if !templateResp.InitialSyncAchieved {
fmt.Println("节点还未完成同步")
return TariBlockTemplate{}, err
}
blk_template, miner_data := templateResp.NewBlockTemplate, templateResp.MinerData
targetDifficulty := miner_data.TargetDifficulty
height := blk_template.Header.Height
blockBlob, err := nc.Client.GetNewBlockBlob(ctx, blk_template)
if err != nil {
fmt.Println("获得block blob失败", err)
return TariBlockTemplate{}, err
}
mining_hash, header, body := blockBlob.BlockHash, blockBlob.Header, blockBlob.BlockBody
var t_bt = TariBlockTemplate{
MiningHash: hex.EncodeToString(mining_hash),
Header: hex.EncodeToString(header),
Body: hex.EncodeToString(body),
TargetDifficulty: targetDifficulty,
Height: height,
}
return t_bt, nil
}
func (nc *BaseNodeClient) SubmitBlock(ctx context.Context, header, body []byte) ([]byte, error) {
submitReq := &base_node.BlockBlobRequest{
HeaderBlob: header,
BodyBlob: body,
}
submitResp, err := nc.Client.SubmitBlockBlob(ctx, submitReq)
if err != nil {
fmt.Println("提交区块失败:", err)
return nil, err
}
blockHash := submitResp.BlockHash
return blockHash, nil
}

View File

@ -64,7 +64,6 @@ type Sha3xStratumJob struct {
Header string `json:"header, omitempty"`
NBits string `json:"nBits, omitempty"`
Id uint64 `json:"id, omitempty"`
JobId string `json:"job_id", omitempty`
CurTime uint64 `json:"timestamp, omitempty"`
Target string `json:"target, omitempty"`
Height uint32 `json:"height, omitempty"`
@ -89,29 +88,6 @@ type BlockSha3xMsg struct {
SubmitIdx uint64 `json:"submitidx"`
}
type Sha3xJob struct {
JobId string
MiningHash string
Height uint64
Header string
Body string
TargetDifficulty uint64
}
type GbtSendMsg struct {
Id uint64
JobId string
MiningHash string
Header string
TargetDifficulty uint64
Height uint64
Target string
Nonce string
Extranonce1 string `json:"extranonce1, omitempty"`
Extranonce2_size uint64 `json:"extranonce2_size, omitempty"`
Extranonce2 string `json:"extranonce2, omitempty"`
}
type MonoreBlockTemplate struct {
BlockhashingBlob string `json:"blockhashing_blob"`
BlocktemplateBlob string `json:"blocktemplate_blob"`