This repository has been archived by the owner on Mar 23, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
53 changed files
with
4,207 additions
and
0 deletions.
There are no files selected for viewing
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,40 @@ | ||
[package] | ||
name = "blockchain_contracts" | ||
version = "0.1.0" | ||
authors = ["CoBloX developers <team@coblox.tech>"] | ||
edition = "2018" | ||
description = "Blockchain contracts used by COMIT-network daemons to execute cryptographic protocols." | ||
|
||
[dependencies] | ||
byteorder = "1.3" | ||
hex = "0.4" | ||
hex-literal = "0.2" | ||
itertools = "0.8.0" | ||
regex = "1.3" | ||
rust_bitcoin = { version = "0.19.1", package = "bitcoin" } | ||
serde = { version = "1.0", features = ["derive"] } | ||
serde_json = "1.0" | ||
tiny-keccak = "1.5" | ||
web3 = { version = "0.8", default-features = false, features = ["http"] } | ||
|
||
[dev-dependencies] | ||
bitcoincore-rpc = "0.8.0-rc1" | ||
failure = "0.1" | ||
lazy_static = "1.4" | ||
log = "0.4" | ||
pretty_env_logger = "0.3" | ||
rust-crypto = "0.2" | ||
spectral = "0.6" | ||
testcontainers = "0.8" | ||
tiny-keccak = "1.5" | ||
|
||
# These versions need to be changed together with web3, depends on what version of primitive-types ships with web3 | ||
[dev-dependencies.primitive-types] | ||
features = ["rlp"] | ||
version = "0.5.0" | ||
|
||
[dev-dependencies.rlp] | ||
version = "0.4.2" | ||
|
||
[build-dependencies] | ||
regex = "1.3" |
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 @@ | ||
pub mod rfc003; |
34 changes: 34 additions & 0 deletions
34
src/bin/calculate_offsets/bitcoin/rfc003/compile_contract.rs
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,34 @@ | ||
use crate::calculate_offsets::{bitcoin::rfc003::Error, check_bin_in_path}; | ||
use std::{ | ||
ffi::OsStr, | ||
io::Write, | ||
path::Path, | ||
process::{Command, Stdio}, | ||
}; | ||
|
||
pub fn compile<S: AsRef<OsStr>>(file_path: S) -> Result<Vec<u8>, Error> { | ||
check_bin_in_path("docker"); | ||
let mut bx = Command::new("docker") | ||
.arg("run") | ||
.arg("--rm") | ||
.arg("-i") | ||
.arg("coblox/libbitcoin-explorer:latest") | ||
.arg("script-encode") | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.stderr(Stdio::null()) | ||
.spawn()?; | ||
|
||
let input = std::fs::read(Path::new(&file_path))?; | ||
let input = String::from_utf8(input)?; | ||
let input = input.replace("\n", " ").into_bytes(); | ||
|
||
let stdin = bx.stdin.as_mut().ok_or(Error::CannotWriteInStdin)?; | ||
stdin.write_all(&input)?; | ||
|
||
let output = bx.wait_with_output()?; | ||
let stdout = String::from_utf8(output.stdout)?; | ||
let bytes = hex::decode(stdout.trim())?; | ||
|
||
Ok(bytes) | ||
} |
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,92 @@ | ||
use crate::calculate_offsets::{ | ||
self, concat_path, | ||
metadata::Metadata, | ||
placeholder_config::{self, PlaceholderConfig}, | ||
Contract, | ||
}; | ||
use std::{ffi::OsStr, path::Path, string::FromUtf8Error}; | ||
|
||
mod compile_contract; | ||
|
||
pub struct BitcoinScript { | ||
bytes: Vec<u8>, | ||
placeholder_config: PlaceholderConfig, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
CalculateOffset(calculate_offsets::Error), | ||
PlaceholderConfig(placeholder_config::Error), | ||
Hex(hex::FromHexError), | ||
IO(std::io::Error), | ||
MalformedRegex(regex::Error), | ||
CannotWriteInStdin, | ||
MalformedInput(FromUtf8Error), | ||
} | ||
|
||
impl From<calculate_offsets::Error> for Error { | ||
fn from(err: calculate_offsets::Error) -> Self { | ||
Error::CalculateOffset(err) | ||
} | ||
} | ||
|
||
impl From<placeholder_config::Error> for Error { | ||
fn from(err: placeholder_config::Error) -> Self { | ||
Error::PlaceholderConfig(err) | ||
} | ||
} | ||
|
||
impl From<std::io::Error> for Error { | ||
fn from(err: std::io::Error) -> Self { | ||
Error::IO(err) | ||
} | ||
} | ||
|
||
impl From<regex::Error> for Error { | ||
fn from(e: regex::Error) -> Self { | ||
Error::MalformedRegex(e) | ||
} | ||
} | ||
|
||
impl From<hex::FromHexError> for Error { | ||
fn from(e: hex::FromHexError) -> Self { | ||
Error::Hex(e) | ||
} | ||
} | ||
|
||
impl From<FromUtf8Error> for Error { | ||
fn from(err: FromUtf8Error) -> Self { | ||
Error::MalformedInput(err) | ||
} | ||
} | ||
|
||
impl Contract for BitcoinScript { | ||
type Error = Error; | ||
|
||
fn compile<S: AsRef<OsStr>>(template_folder: S) -> Result<Self, Self::Error> { | ||
let bytes = compile_contract::compile(Path::new(&template_folder).join("contract.script"))?; | ||
|
||
let placeholder_config = | ||
PlaceholderConfig::from_file(concat_path(&template_folder, "config.json"))?; | ||
Ok(Self { | ||
bytes, | ||
placeholder_config, | ||
}) | ||
} | ||
|
||
fn metadata(&self) -> Metadata { | ||
Metadata { | ||
ledger_name: self.placeholder_config.ledger_name.to_owned(), | ||
asset_name: self.placeholder_config.asset_name.to_owned(), | ||
contract: self.bytes.to_owned(), | ||
} | ||
} | ||
|
||
fn placeholder_config(&self) -> &PlaceholderConfig { | ||
&self.placeholder_config | ||
} | ||
|
||
fn bytes(&self) -> &[u8] { | ||
self.bytes.as_slice() | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/bin/calculate_offsets/bitcoin/rfc003/templates/bitcoin/config.json
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,22 @@ | ||
{ | ||
"ledger_name": "Bitcoin", | ||
"asset_name": "Bitcoin", | ||
"placeholders": [ | ||
{ | ||
"name": "secret_hash", | ||
"replace_pattern": "1000000000000000000000000000000000000000000000000000000000000001" | ||
}, | ||
{ | ||
"name": "refund_timestamp", | ||
"replace_pattern": "20000002" | ||
}, | ||
{ | ||
"name": "redeem_identity", | ||
"replace_pattern": "3000000000000000000000000000000000000003" | ||
}, | ||
{ | ||
"name": "refund_identity", | ||
"replace_pattern": "4000000000000000000000000000000000000004" | ||
} | ||
] | ||
} |
10 changes: 10 additions & 0 deletions
10
src/bin/calculate_offsets/bitcoin/rfc003/templates/bitcoin/contract.script
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,10 @@ | ||
IF | ||
SIZE 32 EQUALVERIFY | ||
SHA256 [1000000000000000000000000000000000000000000000000000000000000001] EQUALVERIFY | ||
DUP HASH160 [3000000000000000000000000000000000000003] | ||
ELSE | ||
[20000002] CHECKLOCKTIMEVERIFY DROP | ||
DUP HASH160 [4000000000000000000000000000000000000004] | ||
ENDIF | ||
EQUALVERIFY | ||
CHECKSIG |
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,13 @@ | ||
use serde::{Deserialize, Serialize}; | ||
use web3::types::Bytes; | ||
|
||
pub mod rfc003; | ||
|
||
#[derive(Deserialize, Serialize, Debug)] | ||
pub struct ByteCode(pub String); | ||
|
||
impl Into<Bytes> for ByteCode { | ||
fn into(self) -> Bytes { | ||
Bytes(hex::decode(self.0).unwrap()) | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/bin/calculate_offsets/ethereum/rfc003/compile_contract.rs
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,51 @@ | ||
use crate::calculate_offsets::{check_bin_in_path, ethereum::rfc003::Error}; | ||
use regex::Regex; | ||
use std::{ | ||
env::var, | ||
ffi::OsStr, | ||
process::{Command, Stdio}, | ||
}; | ||
|
||
pub fn compile<S: AsRef<OsStr>>(file_path: S) -> Result<Vec<u8>, Error> { | ||
let solc_bin = var("SOLC_BIN"); | ||
|
||
let mut solc = match solc_bin { | ||
Ok(bin) => Command::new(bin) | ||
.arg("--assemble") | ||
.arg("-") | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.stderr(Stdio::null()) | ||
.spawn()?, | ||
Err(_) => { | ||
check_bin_in_path("docker"); | ||
Command::new("docker") | ||
.arg("run") | ||
.arg("--rm") | ||
.arg("-i") | ||
.arg("ethereum/solc:0.4.24") | ||
.arg("--assemble") | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.stderr(Stdio::null()) | ||
.spawn()? | ||
} | ||
}; | ||
|
||
let mut file = ::std::fs::File::open(OsStr::new(&file_path))?; | ||
|
||
::std::io::copy(&mut file, solc.stdin.as_mut().unwrap())?; | ||
|
||
let output = solc.wait_with_output()?; | ||
let stdout = String::from_utf8(output.stdout).unwrap(); | ||
let regex = Regex::new(r"\nBinary representation:\n(?P<hexcode>.+)\n")?; | ||
|
||
let captures = regex | ||
.captures(stdout.as_str()) | ||
.expect("Regex didn't match!"); | ||
|
||
let hexcode = captures.name("hexcode").ok_or(Error::CaptureSolcBytecode)?; | ||
let bytes = hex::decode(hexcode.as_str())?; | ||
|
||
Ok(bytes) | ||
} |
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,104 @@ | ||
extern crate regex; | ||
use crate::calculate_offsets::{ | ||
calc_offset, concat_path, | ||
ethereum::rfc003::{compile_contract::compile, Error}, | ||
metadata::Metadata, | ||
placeholder_config::{Placeholder, PlaceholderConfig}, | ||
Contract, | ||
}; | ||
use byteorder::{BigEndian, ByteOrder}; | ||
use std::{convert::TryFrom, ffi::OsStr}; | ||
|
||
pub struct EthereumContract { | ||
bytes: Vec<u8>, | ||
placeholder_config: PlaceholderConfig, | ||
} | ||
|
||
impl EthereumContract { | ||
fn replace_contract_offset_parameters_in_header( | ||
header: &mut [u8], | ||
body: &[u8], | ||
) -> Result<(), Error> { | ||
let body_length = body.len(); | ||
let header_length = header.len(); | ||
|
||
Self::replace_offset_parameter_in_header( | ||
"1001", | ||
"start of contract when loading into memory", | ||
header_length, | ||
header, | ||
)?; | ||
Self::replace_offset_parameter_in_header( | ||
"2002", | ||
"end of contract when loading into memory", | ||
body_length, | ||
header, | ||
)?; | ||
Self::replace_offset_parameter_in_header( | ||
"3003", | ||
"length of contract when returning for execution", | ||
body_length, | ||
header, | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
fn replace_offset_parameter_in_header( | ||
replace_pattern: &str, | ||
name: &str, | ||
value: usize, | ||
header: &mut [u8], | ||
) -> Result<(), Error> { | ||
let header_placeholder = Placeholder { | ||
name: name.into(), | ||
replace_pattern: replace_pattern.into(), | ||
}; | ||
|
||
let header_placeholder_offset = calc_offset(&header_placeholder, header)?; | ||
|
||
let header_slice = | ||
&mut header[header_placeholder_offset.start..header_placeholder_offset.excluded_end]; | ||
|
||
BigEndian::write_u16(header_slice, u16::try_from(value)?); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl Contract for EthereumContract { | ||
type Error = crate::calculate_offsets::ethereum::rfc003::Error; | ||
|
||
fn compile<S: AsRef<OsStr>>(template_folder: S) -> Result<EthereumContract, Error> { | ||
let mut bytes = compile(concat_path(&template_folder, "deploy_header.asm"))?; | ||
let mut contract_body = compile(concat_path(&template_folder, "contract.asm"))?; | ||
|
||
Self::replace_contract_offset_parameters_in_header(&mut bytes, &contract_body)?; | ||
|
||
bytes.append(&mut contract_body); | ||
|
||
let placeholder_config = | ||
PlaceholderConfig::from_file(concat_path(&template_folder, "config.json"))?; | ||
|
||
Ok(Self { | ||
bytes, | ||
placeholder_config, | ||
}) | ||
} | ||
|
||
fn metadata(&self) -> Metadata { | ||
Metadata { | ||
ledger_name: self.placeholder_config.ledger_name.to_owned(), | ||
asset_name: self.placeholder_config.asset_name.to_owned(), | ||
contract: self.bytes.to_owned(), | ||
} | ||
} | ||
|
||
fn placeholder_config(&self) -> &PlaceholderConfig { | ||
&self.placeholder_config | ||
} | ||
|
||
fn bytes(&self) -> &[u8] { | ||
self.bytes.as_slice() | ||
} | ||
} |
Oops, something went wrong.