-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from consenlabs/feature/bls-to-execution-change
feat: add BLSToExecutionEhange signature feature
- Loading branch information
Showing
12 changed files
with
407 additions
and
10 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
2.5.0 | ||
2.6.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
use crate::hex_to_bytes; | ||
use lazy_static::lazy_static; | ||
use ssz_rs::prelude::*; | ||
use ssz_rs::{Node, Vector}; | ||
use std::collections::HashMap; | ||
use std::convert::{TryFrom, TryInto}; | ||
use std::str::FromStr; | ||
|
||
const DOMAIN_LEN: usize = 32; | ||
const DOMAIN_TYPE_LEN: usize = 4; | ||
const BLS_PUBKEY_LEN: usize = 48; | ||
const EXECUTION_ADDR_LEN: usize = 20; | ||
type DomainType = Vector<u8, DOMAIN_TYPE_LEN>; | ||
type Domain = Vector<u8, DOMAIN_LEN>; | ||
type Version = Vector<u8, 4>; | ||
type BLSPubkey = Vector<u8, BLS_PUBKEY_LEN>; | ||
type ExecutionAddress = Vector<u8, EXECUTION_ADDR_LEN>; | ||
|
||
lazy_static! { | ||
static ref DOMAIN_BLS_TO_EXECUTION_CHANGE: DomainType = | ||
Vector::<u8, DOMAIN_TYPE_LEN>::deserialize(&[0x0A, 0, 0, 0]) | ||
.expect("failed to deserialize"); | ||
} | ||
|
||
impl BLSToExecutionRequest { | ||
pub fn generate_bls_to_execution_change_hash(&self) -> tcx_constants::Result<String> { | ||
let to_execution_address_bytes = hex_to_bytes(&self.to_execution_address)?; | ||
let to_execution_address = | ||
Vector::<u8, EXECUTION_ADDR_LEN>::deserialize(to_execution_address_bytes.as_ref())?; | ||
let from_bls_pubkey_bytes = hex_to_bytes(&self.from_bls_pubkey)?; | ||
let from_bls_pubkey = | ||
Vector::<u8, BLS_PUBKEY_LEN>::deserialize(from_bls_pubkey_bytes.as_ref())?; | ||
let validator_index = self.validator_index; | ||
let message = BLSToExecutionChange { | ||
validator_index, | ||
from_bls_pubkey, | ||
to_execution_address, | ||
}; | ||
|
||
let fork_version = Vector::<u8, DOMAIN_TYPE_LEN>::deserialize( | ||
hex_to_bytes(&self.genesis_fork_version)?.as_slice(), | ||
)?; | ||
let validator_root = | ||
Node::try_from(hex_to_bytes(&self.genesis_validators_root)?.as_slice())?; | ||
let domain = compute_domain( | ||
&DOMAIN_BLS_TO_EXECUTION_CHANGE, | ||
fork_version, | ||
&validator_root, | ||
)?; | ||
let signing_root = compute_signing_root(message.clone(), domain)?; | ||
let message = signing_root.as_bytes(); | ||
Ok(hex::encode(message)) | ||
} | ||
} | ||
|
||
pub fn compute_domain( | ||
domain_type: &DomainType, | ||
fork_version: Version, | ||
genesis_validators_root: &Node, | ||
) -> Result<Domain, MerkleizationError> { | ||
if domain_type.len() != 4 { | ||
//todo | ||
} | ||
let fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root)?; | ||
let mut bytes = Vec::new(); | ||
domain_type.serialize(&mut bytes)?; | ||
fork_data_root.serialize(&mut bytes)?; | ||
Ok(Vector::deserialize(&bytes[0..DOMAIN_LEN]).expect("invalid domain data")) | ||
} | ||
|
||
pub fn compute_fork_data_root( | ||
current_version: Version, | ||
genesis_validators_root: &Node, | ||
) -> Result<Node, MerkleizationError> { | ||
ForkData { | ||
current_version, | ||
genesis_validators_root: genesis_validators_root.to_owned(), | ||
} | ||
.hash_tree_root() | ||
} | ||
|
||
pub fn compute_signing_root<T: SimpleSerialize>( | ||
mut ssz_object: T, | ||
domain: Domain, | ||
) -> Result<Node, MerkleizationError> { | ||
SigningData { | ||
object_root: ssz_object.hash_tree_root()?, | ||
domain, | ||
} | ||
.hash_tree_root() | ||
} | ||
|
||
#[derive(SimpleSerialize, Default)] | ||
pub struct ForkData { | ||
current_version: Version, | ||
genesis_validators_root: Node, | ||
} | ||
|
||
#[derive(SimpleSerialize, Default)] | ||
pub struct SigningData { | ||
object_root: Node, | ||
domain: Domain, | ||
} | ||
|
||
#[derive(SimpleSerialize, Default, Clone, Debug)] | ||
pub struct BLSToExecutionChange { | ||
validator_index: u32, | ||
from_bls_pubkey: BLSPubkey, | ||
to_execution_address: ExecutionAddress, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct BLSToExecutionRequest { | ||
pub genesis_fork_version: String, | ||
pub genesis_validators_root: String, | ||
pub validator_index: u32, | ||
pub from_bls_pubkey: String, | ||
pub to_execution_address: String, | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::bls_to_execution_change::BLSToExecutionRequest; | ||
use crate::transaction::SignBlsToExecutionChangeParam; | ||
use tcx_chain::Keystore; | ||
|
||
#[test] | ||
fn test_generate_bls_to_execution_change_hash() { | ||
let mut blsToExecutionRequest = BLSToExecutionRequest { | ||
genesis_fork_version: "0x03000000".to_string(), | ||
genesis_validators_root: "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95".to_string(), | ||
validator_index: 0, | ||
from_bls_pubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db".to_string(), | ||
to_execution_address: "0x8c1Ff978036F2e9d7CC382Eff7B4c8c53C22ac15".to_string(), | ||
}; | ||
let ret_data = blsToExecutionRequest | ||
.generate_bls_to_execution_change_hash() | ||
.expect("generate_bls_to_execution_change_hash_error"); | ||
assert_eq!( | ||
ret_data, | ||
"23ba0fe9dc5d2fae789f31fdccb4e28e74b89aec26bafdd6c96ced598542f53e" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,23 @@ | ||
extern crate core; | ||
|
||
pub mod address; | ||
mod bls_to_execution_change; | ||
pub mod signer; | ||
pub mod transaction; | ||
use failure::Fail; | ||
use tcx_chain::Result; | ||
|
||
#[derive(Fail, Debug, PartialEq)] | ||
pub enum Error { | ||
#[fail(display = "invalid_hex_value")] | ||
InvalidHexValue, | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
#[test] | ||
fn it_works() { | ||
assert_eq!(2 + 2, 4); | ||
} | ||
pub fn hex_to_bytes(value: &str) -> Result<Vec<u8>> { | ||
let result = if value.starts_with("0x") || value.starts_with("0X") { | ||
hex::decode(&value[2..]) | ||
} else { | ||
hex::decode(&value[..]) | ||
}; | ||
result.map_err(|_| Error::InvalidHexValue.into()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use crate::bls_to_execution_change::{compute_domain, BLSToExecutionRequest}; | ||
use crate::transaction::{ | ||
BlsToExecutionChangeMessage, SignBlsToExecutionChangeParam, SignBlsToExecutionChangeResult, | ||
SignedBlsToExecutionChange, | ||
}; | ||
use crate::{hex_to_bytes, Error, Result}; | ||
use ssz_rs::{Deserialize, Vector}; | ||
use tcx_chain::{ | ||
ChainSigner, Keystore, KeystoreGuard, TransactionSigner as TraitTransactionSigner, | ||
}; | ||
|
||
impl SignBlsToExecutionChangeParam { | ||
pub fn sign_bls_to_execution_change( | ||
&self, | ||
keystore: &mut Keystore, | ||
) -> Result<SignBlsToExecutionChangeResult> { | ||
let mut blsToExecutionRequest = BLSToExecutionRequest { | ||
genesis_fork_version: self.genesis_fork_version.to_string(), | ||
genesis_validators_root: self.genesis_validators_root.to_string(), | ||
validator_index: 0, | ||
from_bls_pubkey: self.from_bls_pub_key.to_string(), | ||
to_execution_address: self.eth1_withdrawal_address.to_string(), | ||
}; | ||
let mut signeds = vec![]; | ||
for validator_index in &self.validator_index { | ||
blsToExecutionRequest.validator_index = *validator_index; | ||
let message = blsToExecutionRequest.generate_bls_to_execution_change_hash()?; | ||
|
||
let signature = keystore.sign_hash( | ||
hex::decode(message)?.as_slice(), | ||
"ETHEREUM2", | ||
self.from_bls_pub_key.as_str(), | ||
None, | ||
)?; | ||
let blsToExecutionChangeMessage = BlsToExecutionChangeMessage { | ||
validator_index: *validator_index, | ||
from_bls_pubkey: self.from_bls_pub_key.to_string(), | ||
to_execution_address: self.eth1_withdrawal_address.to_string(), | ||
}; | ||
let signedBlsToExecutionChange = SignedBlsToExecutionChange { | ||
message: Some(blsToExecutionChangeMessage), | ||
signature: hex::encode(signature), | ||
}; | ||
signeds.push(signedBlsToExecutionChange); | ||
} | ||
|
||
let signBlsToExecutionChangeResult = SignBlsToExecutionChangeResult { signeds }; | ||
Ok(signBlsToExecutionChangeResult) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct SignBlsToExecutionChangeParam { | ||
#[prost(string, tag = "1")] | ||
pub id: ::prost::alloc::string::String, | ||
#[prost(string, tag = "2")] | ||
pub password: ::prost::alloc::string::String, | ||
#[prost(string, tag = "3")] | ||
pub genesis_fork_version: ::prost::alloc::string::String, | ||
#[prost(string, tag = "4")] | ||
pub genesis_validators_root: ::prost::alloc::string::String, | ||
#[prost(uint32, repeated, tag = "5")] | ||
pub validator_index: ::prost::alloc::vec::Vec<u32>, | ||
#[prost(string, tag = "6")] | ||
pub from_bls_pub_key: ::prost::alloc::string::String, | ||
#[prost(string, tag = "7")] | ||
pub eth1_withdrawal_address: ::prost::alloc::string::String, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct SignBlsToExecutionChangeResult { | ||
#[prost(message, repeated, tag = "1")] | ||
pub signeds: ::prost::alloc::vec::Vec<SignedBlsToExecutionChange>, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct SignedBlsToExecutionChange { | ||
#[prost(message, optional, tag = "1")] | ||
pub message: ::core::option::Option<BlsToExecutionChangeMessage>, | ||
#[prost(string, tag = "2")] | ||
pub signature: ::prost::alloc::string::String, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct BlsToExecutionChangeMessage { | ||
#[prost(uint32, tag = "1")] | ||
pub validator_index: u32, | ||
#[prost(string, tag = "2")] | ||
pub from_bls_pubkey: ::prost::alloc::string::String, | ||
#[prost(string, tag = "3")] | ||
pub to_execution_address: ::prost::alloc::string::String, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
syntax = "proto3"; | ||
package transaction; | ||
message SignBLSToExecutionChangeParam { | ||
string id = 1; | ||
string password = 2; | ||
string genesisForkVersion = 3; | ||
string genesisValidatorsRoot = 4; | ||
repeated uint32 validatorIndex = 5; | ||
string fromBlsPubKey = 6; | ||
string eth1WithdrawalAddress = 7; | ||
} | ||
|
||
message SignBLSToExecutionChangeResult { | ||
repeated SignedBLSToExecutionChange signeds = 1; | ||
} | ||
|
||
message SignedBLSToExecutionChange { | ||
BLSToExecutionChangeMessage message = 1; | ||
string signature = 2; | ||
} | ||
|
||
message BLSToExecutionChangeMessage{ | ||
uint32 validator_index = 1; | ||
string from_bls_pubkey = 2; | ||
string to_execution_address = 3; | ||
} |
Oops, something went wrong.