ExtendedExtranonce

Struct ExtendedExtranonce 

Source
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_00..0: There is no upstream relative to the pool P, so no space is reserved by the upstream.
  • range_10..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 as static_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_216..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_00..16: These bytes are set by the upstream and P shouldn’t change them.
  • range_116..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_224..32: These bytes are left free for the Sv1 mining device.

Scenario 3: P is an Sv1 mining device

  • range_00..24: These bytes are set by the device’s upstreams.
  • range_124..32: These bytes are changed by P (if capable) to increment the search space.
  • range_232..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

Source

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.

Source

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>

Source

pub fn get_len(&self) -> usize

Source

pub fn get_range2_len(&self) -> usize

Source

pub fn get_range0_len(&self) -> usize

Source

pub fn get_prefix_len(&self) -> usize

Source

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.

Source

pub fn extranonce_from_downstream_extranonce( &self, dowstream_extranonce: Extranonce, ) -> Result<Extranonce, ExtendedExtranonceError>

Source

pub fn next_prefix_standard( &mut self, ) -> Result<Extranonce, ExtendedExtranonceError>

Calculates the next extranonce for standard channels.

Source

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.

Source

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

Source

pub fn upstream_part(&self) -> Extranonce

Trait Implementations§

Source§

impl Clone for ExtendedExtranonce

Source§

fn clone(&self) -> ExtendedExtranonce

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ExtendedExtranonce

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<&mut ExtendedExtranonce> for Extranonce

Source§

fn from(v: &mut ExtendedExtranonce) -> Self

Converts to this type from the input type.
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], }

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.