Skip to content
This repository has been archived by the owner on Mar 23, 2021. It is now read-only.

Commit

Permalink
Bring the code in from comit-rs
Browse files Browse the repository at this point in the history
  • Loading branch information
D4nte committed Oct 11, 2019
1 parent 4c3ede4 commit fe35482
Show file tree
Hide file tree
Showing 53 changed files with 4,207 additions and 0 deletions.
40 changes: 40 additions & 0 deletions Cargo.toml
@@ -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"
1 change: 1 addition & 0 deletions src/bin/calculate_offsets/bitcoin/mod.rs
@@ -0,0 +1 @@
pub mod rfc003;
34 changes: 34 additions & 0 deletions src/bin/calculate_offsets/bitcoin/rfc003/compile_contract.rs
@@ -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)
}
92 changes: 92 additions & 0 deletions src/bin/calculate_offsets/bitcoin/rfc003/mod.rs
@@ -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()
}
}
@@ -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"
}
]
}
@@ -0,0 +1,10 @@
IF
SIZE 32 EQUALVERIFY
SHA256 [1000000000000000000000000000000000000000000000000000000000000001] EQUALVERIFY
DUP HASH160 [3000000000000000000000000000000000000003]
ELSE
[20000002] CHECKLOCKTIMEVERIFY DROP
DUP HASH160 [4000000000000000000000000000000000000004]
ENDIF
EQUALVERIFY
CHECKSIG
13 changes: 13 additions & 0 deletions src/bin/calculate_offsets/ethereum/mod.rs
@@ -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 src/bin/calculate_offsets/ethereum/rfc003/compile_contract.rs
@@ -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)
}
104 changes: 104 additions & 0 deletions src/bin/calculate_offsets/ethereum/rfc003/contract.rs
@@ -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()
}
}

0 comments on commit fe35482

Please sign in to comment.