pub struct ExtendedExtranonce { /* private fields */ }Expand description
Downstream and upstream are relative to user P. In simple terms, upstream is the part of the protocol that a user P sees when looking above, and downstream is what they see when looking below.
An ExtendedExtranonce is defined by 3 ranges:
-
range_0: Represents the extended extranonce part reserved by upstream relative to P (for most upstream nodes, e.g., a pool, this is[0..0]) and it is fixed for P. -
range_1: Represents the extended extranonce part reserved for P. P assigns to every relative downstream a unique extranonce with different values in range_1 in the following way: if D_i is the (i+1)-th downstream that connected to P, then D_i gets from P an extranonce with range_1=i (note that the concatenation of range_0 and range_1 is the range_0 relative to D_i, and range_2 of P is the range_1 of D_i). -
range_2: Represents the range that P reserves for the downstreams.
In the following scenarios, we examine the extended extranonce in some cases:
Scenario 1: P is a pool
range_0→0..0: There is no upstream relative to the pool P, so no space is reserved by the upstream.range_1→0..16: The pool P increments these bytes to ensure each downstream gets a unique extended extranonce search space. The pool could optionally choose to set some fixed bytes asstatic_prefix(no bigger than 2 bytes), which are set on the beginning of this range and will not be incremented. These bytes are used to allow unique allocation for the pool’s mining server (if there are more than one).range_2→16..32: These bytes are not changed by the pool but are changed by the pool’s downstream.
Scenario 2: P is a translator proxy
range_0→0..16: These bytes are set by the upstream and P shouldn’t change them.range_1→16..24: These bytes are modified by P each time an Sv1 mining device connects, ensuring each connected Sv1 mining device gets a different extended extranonce search space.range_2→24..32: These bytes are left free for the Sv1 mining device.
Scenario 3: P is an Sv1 mining device
range_0→0..24: These bytes are set by the device’s upstreams.range_1→24..32: These bytes are changed by P (if capable) to increment the search space.range_2→32..32: No more downstream.
§Examples
Basic usage without static prefix:
use mining_sv2::*;
use core::convert::TryInto;
// Create an extended extranonce of len 32, reserving the first 7 bytes for the pool
let mut pool_extended_extranonce = ExtendedExtranonce::new(0..0, 0..7, 7..32, None).unwrap();
// On open extended channel (requesting to use a range of 4 bytes), the pool allocates this extranonce_prefix:
let new_extended_channel_extranonce_prefix = pool_extended_extranonce.next_prefix_extended(4).unwrap();
let expected_extranonce_prefix = vec![0, 0, 0, 0, 0, 0, 1];
assert_eq!(new_extended_channel_extranonce_prefix.clone().to_vec(), expected_extranonce_prefix);
// On open extended channel (requesting to use a range of 20 bytes), the pool allocates this extranonce_prefix:
let new_extended_channel_extranonce_prefix = pool_extended_extranonce.next_prefix_extended(20).unwrap();
let expected_extranonce_prefix = vec![0, 0, 0, 0, 0, 0, 2];
assert_eq!(new_extended_channel_extranonce_prefix.clone().to_vec(), expected_extranonce_prefix);
// On open extended channel (requesting to use a range of 26 bytes, which is too much), we get an error:
let new_extended_channel_extranonce_prefix_error = pool_extended_extranonce.next_prefix_extended(26);
assert!(new_extended_channel_extranonce_prefix_error.is_err());
// Then the pool receives a request to open a standard channel
let new_standard_channel_extranonce = pool_extended_extranonce.next_prefix_standard().unwrap();
// For standard channels, only the bytes in range_2 are incremented
let expected_standard_extranonce = vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
assert_eq!(new_standard_channel_extranonce.to_vec(), expected_standard_extranonce);
// Now the proxy receives the ExtendedExtranonce previously created
// The proxy knows the extranonce space reserved to the pool is 7 bytes and that the total
// extranonce len is 32 bytes and decides to reserve 4 bytes for itself and leave the remaining 21 for
// further downstreams.
let range_0 = 0..7;
let range_1 = 7..11;
let range_2 = 11..32;
let mut proxy_extended_extranonce = ExtendedExtranonce::from_upstream_extranonce(
new_extended_channel_extranonce_prefix,
range_0,
range_1,
range_2
).unwrap();
// The proxy generates an extended extranonce for downstream (allowing it to use a range of 3 bytes)
let new_extended_channel_extranonce_prefix = proxy_extended_extranonce.next_prefix_extended(3).unwrap();
let expected_extranonce_prefix = vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1];
assert_eq!(new_extended_channel_extranonce_prefix.clone().to_vec(), expected_extranonce_prefix);
// When the proxy receives a share from downstream and wants to recreate the full extranonce
// e.g., because it wants to check the share's work
let received_extranonce: Extranonce = vec![0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].try_into().unwrap();
let share_complete_extranonce = proxy_extended_extranonce.extranonce_from_downstream_extranonce(received_extranonce.clone()).unwrap();
let expected_complete_extranonce = vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(share_complete_extranonce.to_vec(), expected_complete_extranonce);
// Now the proxy wants to send the extranonce received from downstream and the part of extranonce
// owned by itself to the pool
let extranonce_to_send = proxy_extended_extranonce.without_upstream_part(Some(received_extranonce)).unwrap();
let expected_extranonce_to_send = vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(extranonce_to_send.to_vec(), expected_extranonce_to_send);Using static prefix:
use mining_sv2::*;
use core::convert::TryInto;
// Create an extended extranonce with a static prefix
let static_prefix = vec![0x42, 0x43]; // Example static prefix
let mut pool_extended_extranonce = ExtendedExtranonce::new(
0..0,
0..7,
7..32,
Some(static_prefix.clone())
).unwrap();
// When using static prefix, only bytes after the static prefix are incremented
let new_extended_channel_extranonce = pool_extended_extranonce.next_prefix_extended(3).unwrap();
let expected_extranonce = vec![0x42, 0x43, 0, 0, 0, 0, 1];
assert_eq!(new_extended_channel_extranonce.clone().to_vec(), expected_extranonce);
// For standard channels, only range_2 is incremented while range_1 (including static prefix) is preserved
let new_standard_channel_extranonce = pool_extended_extranonce.next_prefix_standard().unwrap();
// Note that the static prefix (0x42, 0x43) and the incremented bytes in range_1 are preserved
let expected_standard_extranonce = vec![0x42, 0x43, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
assert_eq!(new_standard_channel_extranonce.to_vec(), expected_standard_extranonce);
// Now the proxy receives the ExtendedExtranonce previously created
// The proxy knows the extranonce space reserved to the pool is 7 bytes and that the total
// extranonce len is 32 bytes and decides to reserve 4 bytes for itself and leave the remaining 21 for
// further downstreams.
let range_0 = 0..7;
let range_1 = 7..11;
let range_2 = 11..32;
let mut proxy_extended_extranonce = ExtendedExtranonce::from_upstream_extranonce(
new_extended_channel_extranonce,
range_0,
range_1,
range_2
).unwrap();
// The proxy generates an extended extranonce for downstream
let new_extended_channel_extranonce_prefix = proxy_extended_extranonce.next_prefix_extended(3).unwrap();
let expected_extranonce_prefix = vec![0x42, 0x43, 0, 0, 0, 0, 1, 0, 0, 0, 1];
assert_eq!(new_extended_channel_extranonce_prefix.clone().to_vec(), expected_extranonce_prefix);
// When the proxy receives a share from downstream and wants to recreate the full extranonce
// e.g., because it wants to check the share's work
let received_extranonce: Extranonce = vec![0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].try_into().unwrap();
let share_complete_extranonce = proxy_extended_extranonce.extranonce_from_downstream_extranonce(received_extranonce.clone()).unwrap();
let expected_complete_extranonce = vec![0x42, 0x43, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(share_complete_extranonce.to_vec(), expected_complete_extranonce);
// Now the proxy wants to send the extranonce received from downstream and the part of extranonce
// owned by itself to the pool
let extranonce_to_send = proxy_extended_extranonce.without_upstream_part(Some(received_extranonce)).unwrap();
let expected_extranonce_to_send = vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];Implementations§
Source§impl ExtendedExtranonce
impl ExtendedExtranonce
Sourcepub fn new(
range_0: Range<usize>,
range_1: Range<usize>,
range_2: Range<usize>,
static_prefix: Option<Vec<u8>>,
) -> Result<Self, ExtendedExtranonceError>
pub fn new( range_0: Range<usize>, range_1: Range<usize>, range_2: Range<usize>, static_prefix: Option<Vec<u8>>, ) -> Result<Self, ExtendedExtranonceError>
every extranonce start from zero.
pub fn new_with_inner_only_test( range_0: Range<usize>, range_1: Range<usize>, range_2: Range<usize>, inner: Vec<u8>, ) -> Result<Self, ExtendedExtranonceError>
pub fn get_len(&self) -> usize
pub fn get_range2_len(&self) -> usize
pub fn get_range0_len(&self) -> usize
pub fn get_prefix_len(&self) -> usize
Sourcepub fn from_upstream_extranonce(
v: Extranonce,
range_0: Range<usize>,
range_1: Range<usize>,
range_2: Range<usize>,
) -> Result<Self, ExtendedExtranonceError>
pub fn from_upstream_extranonce( v: Extranonce, range_0: Range<usize>, range_1: Range<usize>, range_2: Range<usize>, ) -> Result<Self, ExtendedExtranonceError>
Suppose that P receives from the upstream an extranonce that needs to be converted into any ExtendedExtranonce, eg when an extended channel is opened. Then range_0 (that should be provided along the Extranonce) is reserved for the upstream and can’t be modiefied by P. If the bytes recerved to P (range_1 and range_2) are not set to zero, returns None, otherwise returns Some(ExtendedExtranonce). If the range_2.end field is greater than 32, returns None.
Sourcepub fn extranonce_from_downstream_extranonce(
&self,
dowstream_extranonce: Extranonce,
) -> Result<Extranonce, ExtendedExtranonceError>
pub fn extranonce_from_downstream_extranonce( &self, dowstream_extranonce: Extranonce, ) -> Result<Extranonce, ExtendedExtranonceError>
Specular of Self::from_upstream_extranonce
Sourcepub fn next_prefix_standard(
&mut self,
) -> Result<Extranonce, ExtendedExtranonceError>
pub fn next_prefix_standard( &mut self, ) -> Result<Extranonce, ExtendedExtranonceError>
Calculates the next extranonce for standard channels.
Sourcepub fn next_prefix_extended(
&mut self,
required_len: usize,
) -> Result<Extranonce, ExtendedExtranonceError>
pub fn next_prefix_extended( &mut self, required_len: usize, ) -> Result<Extranonce, ExtendedExtranonceError>
Calculates the next extranonce for extended channels. The required_len variable represents the range requested by the downstream to use. The part that is incremented is range_1, as every downstream must have different jobs.
Sourcepub fn without_upstream_part(
&self,
downstream_extranonce: Option<Extranonce>,
) -> Result<Extranonce, ExtendedExtranonceError>
pub fn without_upstream_part( &self, downstream_extranonce: Option<Extranonce>, ) -> Result<Extranonce, ExtendedExtranonceError>
Return a vec with the extranonce bytes that belong to self and downstream removing the ones owned by upstream (using Sv1 terms the extranonce1 is removed) If dowstream_extranonce is Some(v) it replace the downstream extranonce part with v
pub fn upstream_part(&self) -> Extranonce
Trait Implementations§
Source§impl Clone for ExtendedExtranonce
impl Clone for ExtendedExtranonce
Source§fn clone(&self) -> ExtendedExtranonce
fn clone(&self) -> ExtendedExtranonce
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ExtendedExtranonce
impl Debug for ExtendedExtranonce
Source§impl From<&mut ExtendedExtranonce> for Extranonce
impl From<&mut ExtendedExtranonce> for Extranonce
Source§fn from(v: &mut ExtendedExtranonce) -> Self
fn from(v: &mut ExtendedExtranonce) -> Self
Source§impl PartialEq for ExtendedExtranonce
the trait PartialEq is implemented in such a way that only the relevant bytes are compared.
If range_2.end is set to 20, then the following ExtendedExtranonces are equal
ExtendedExtranonce {
inner: [0000 0000 0000 0000 0000 0000 0000 0000],
range_0: [0..5],
range_1: [5..10],
range_2: [10, 20],
}
ExtendedExtranonce {
inner: [0000 0000 0000 0000 0000 1111 1111 1111],
range_0: [0..5],
range_1: [5..10],
range_2: [10, 20],
}
impl PartialEq for ExtendedExtranonce
the trait PartialEq is implemented in such a way that only the relevant bytes are compared. If range_2.end is set to 20, then the following ExtendedExtranonces are equal ExtendedExtranonce { inner: [0000 0000 0000 0000 0000 0000 0000 0000], range_0: [0..5], range_1: [5..10], range_2: [10, 20], } ExtendedExtranonce { inner: [0000 0000 0000 0000 0000 1111 1111 1111], range_0: [0..5], range_1: [5..10], range_2: [10, 20], }