Skip to content

Commit

Permalink
Release Candidate 1 0.13.0 (#154)
Browse files Browse the repository at this point in the history
* Update versions in travis

* Preliminary update of Exonum revision

* Almost ready for release

* Refer python-client instead of launcher

* Improve crate documentation

* Update travis file

* Fix compatibility with rust 1.36

* Release 0.13.0-rc.2

* Make publish check non-fatal
  • Loading branch information
alekseysidorov committed Dec 4, 2019
1 parent dc37080 commit fdbbce9
Show file tree
Hide file tree
Showing 16 changed files with 326 additions and 423 deletions.
17 changes: 10 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ language: rust
addons:
apt:
sources:
- sourceline: 'ppa:exonum/rocksdb'
- sourceline: 'ppa:maarten-fonville/protobuf'
- sourceline: 'ppa:fsgmhoward/shadowsocks-libev'
- sourceline: 'deb [arch=amd64] https://packages.microsoft.com/ubuntu/16.04/prod xenial main'
key_url: https://packages.microsoft.com/keys/microsoft.asc
packages:
- binutils-dev
- build-essential
Expand All @@ -19,18 +16,17 @@ addons:
- libelf-dev
- libiberty-dev
- libprotobuf-dev
- librocksdb5.17
- librocksdb-dev
- libsnappy-dev
- libsodium-dev
- libssl-dev
- pkg-config
- powershell
- protobuf-compiler
- unzip
- zlib1g-dev

rust:
- 1.38.0
- 1.39.0

cache:
npm: true
Expand All @@ -41,7 +37,7 @@ cache:
- $HOME/.local
- $HOME/.kcov

dist: xenial
dist: bionic
sudo: required

env:
Expand Down Expand Up @@ -97,3 +93,10 @@ jobs:
script:
- cargo doc --no-deps
- cargo deadlinks --dir target/doc

# Check publish with Rust 1.36
- name: publish-with-rust-1.36
env: FEATURE=non-fatal-checks
rust: 1.36.0
script:
- cargo publish --dry-run
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

## 0.13.0-rc.2 - 2018-12-04

### Breaking changes

- Ported `exonum-btc-anchoring` to a new version of Exonum with support
Expand Down
29 changes: 11 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "exonum-btc-anchoring"
edition = "2018"
version = "0.12.0"
authors = ["The Exonum Team <exonum@bitfury.com>"]
version = "0.13.0-rc.2"
authors = ["The Exonum Team <contact@exonum.com>"]
homepage = "https://exonum.com/doc/advanced/bitcoin-anchoring/"
repository = "https://github.com/exonum/exonum-btc-anchoring"
documentation = "https://docs.rs/exonum-btc-anchoring"
Expand All @@ -22,16 +22,16 @@ bitcoincore-rpc = "0.7.0"
btc-transaction-utils = "0.6"
byteorder = "1.3"
derive_more = "0.15"
exonum = "0.12.0"
exonum-cli = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-crypto = { features = ["with-protobuf"], git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-derive = "0.12.0"
exonum-merkledb = "0.12.0"
exonum-proto = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-testkit = "0.12.0"
exonum = "0.13.0-rc.2"
exonum-cli = "0.13.0-rc.2"
exonum-crypto = { version = "0.13.0-rc.2", features = ["with-protobuf"] }
exonum-derive = "0.13.0-rc.2"
exonum-merkledb = "0.13.0-rc.2"
exonum-proto = "0.13.0-rc.2"
exonum-supervisor = "0.13.0-rc.2"
exonum-testkit = "0.13.0-rc.2"
failure = "0.1"
failure_derive = "0.1"
futures = "0.1"
hex = "0.4"
jsonrpc = "0.11"
log = "0.4"
Expand All @@ -49,11 +49,4 @@ structopt = "0.3"
proptest = "0.9"

[build-dependencies]
exonum-build = "0.12.0"

[patch.crates-io]
exonum = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-build = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-derive = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-merkledb = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-testkit = { git = "https://github.com/exonum/exonum.git", rev = "7404bacc109da33bdbf5c3a5a09f3f56dae965e8" }
exonum-build = "0.13.0-rc.2"
4 changes: 2 additions & 2 deletions guides/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ the behavior of the anchoring node is undefined.*

## Modification of Configuration Parameters

You can use the [`exonum_launcher`][exonum_launcher] utility to change the
You can use the [`exonum-python-client`][exonum-python-client] utility to change the
anchoring configuration.

List of parameters that you can change without any preparatory actions:
Expand Down Expand Up @@ -72,5 +72,5 @@ in the next section.

[anchoring:actual-address]: https://exonum.com/doc/version/latest/advanced/bitcoin-anchoring/#actual-address
[anchoring:add-funds]: https://exonum.com/doc/version/latest/advanced/bitcoin-anchoring/#add-funds
[exonum_launcher]: https://github.com/popzxc/exonum-launcher
[exonum-python-client]: https://github.com/exonum/exonum-python-client
[newbie_guide:step-3]: newbie.md#step-3-deploying-and-running
124 changes: 45 additions & 79 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@

use btc_transaction_utils::{p2wsh, TxInRef};
use exonum::{
blockchain::{BlockProof, IndexCoordinates, IndexOwner, Schema as CoreSchema},
blockchain::{BlockProof, IndexCoordinates, SchemaOrigin},
crypto::Hash,
helpers::Height,
merkledb::{ListProof, MapProof, ObjectHash, Snapshot},
runtime::{
runtime::rust::{
api::{self, ServiceApiBuilder, ServiceApiState},
rust::Transaction,
Transaction,
},
};
use exonum_merkledb::{ListProof, MapProof};
use failure::ensure;
use futures::{Future, IntoFuture, Sink};
use serde_derive::{Deserialize, Serialize};

use std::cmp::{
Expand All @@ -35,7 +34,7 @@ use std::cmp::{
};

use crate::{
blockchain::{AddFunds, BtcAnchoringSchema, SignInput},
blockchain::{AddFunds, Schema, SignInput, Transactions},
btc,
config::Config,
};
Expand Down Expand Up @@ -140,20 +139,14 @@ pub trait PrivateApi {
/// by the current node, and returns its hash.
///
/// `POST /{api_prefix}/sign-input`
fn sign_input(
&self,
sign_input: SignInput,
) -> Box<dyn Future<Item = Hash, Error = Self::Error>>;
fn sign_input(&self, sign_input: SignInput) -> Result<Hash, Self::Error>;
/// Adds funds via suitable funding transaction.
///
/// Bitcoin transaction should have output with value to the current anchoring address.
/// The transaction will be applied if 2/3+1 anchoring nodes sent it.
///
/// `POST /{api_prefix}/add-funds`
fn add_funds(
&self,
transaction: btc::Transaction,
) -> Box<dyn Future<Item = Hash, Error = Self::Error>>;
fn add_funds(&self, transaction: btc::Transaction) -> Result<Hash, Self::Error>;
/// Returns a proposal for the next anchoring transaction, if it makes sense.
/// If there is not enough satoshis to create a proposal an error is returned.
///
Expand All @@ -176,38 +169,21 @@ pub trait PrivateApi {
struct ApiImpl<'a>(&'a ServiceApiState<'a>);

impl<'a> ApiImpl<'a> {
fn anchoring_schema(&self) -> BtcAnchoringSchema<&'a dyn Snapshot> {
BtcAnchoringSchema::new(self.0.instance.name, self.0.snapshot())
}

fn broadcast_transaction(
&self,
transaction: impl Transaction,
) -> impl Future<Item = Hash, Error = failure::Error> {
use exonum::node::ExternalMessage;

let keypair = self.0.service_keypair;
let signed = transaction.sign(self.0.instance.id, keypair.0, &keypair.1);

let hash = signed.object_hash();
// TODO Move this code to core
self.0
.sender()
.clone()
.0
.send(ExternalMessage::Transaction(signed))
.map(move |_| hash)
.map_err(From::from)
transaction: impl Transaction<dyn Transactions + 'static>,
) -> Result<Hash, failure::Error> {
self.0.generic_broadcaster().send(transaction)
}

fn actual_config(&self) -> Result<Config, failure::Error> {
Ok(BtcAnchoringSchema::new(self.0.instance.name, self.0.snapshot()).actual_config())
Ok(Schema::new(self.0.service_data()).actual_config())
}

fn verify_sign_input(&self, sign_input: &SignInput) -> Result<(), failure::Error> {
let schema = self.anchoring_schema();
let schema = Schema::new(self.0.service_data());
let (proposal, inputs) = schema
.actual_proposed_anchoring_transaction()
.actual_proposed_anchoring_transaction(self.0.data().for_core())
.ok_or_else(|| failure::format_err!("Anchoring transaction proposal is absent."))??;

// Verify transaction content.
Expand All @@ -218,7 +194,7 @@ impl<'a> ApiImpl<'a> {
// Find corresponding Bitcoin key.
let config = schema.actual_config();
let bitcoin_key = config
.find_bitcoin_key(&self.0.service_keypair.0)
.find_bitcoin_key(&self.0.service_key())
.ok_or_else(|| failure::format_err!("This node is not an anchoring node."))?
.1;

Expand All @@ -236,10 +212,10 @@ impl<'a> ApiImpl<'a> {
fn verify_funding_tx(&self, tx: &btc::Transaction) -> Result<(), failure::Error> {
let txid = tx.id();

let schema = self.anchoring_schema();
let schema = Schema::new(self.0.service_data());
let config = schema.actual_config();
ensure!(
!schema.spent_funding_transactions().contains(&txid),
!schema.spent_funding_transactions.contains(&txid),
"Funding transaction {} has been already used.",
txid
);
Expand All @@ -252,17 +228,17 @@ impl<'a> ApiImpl<'a> {
}

fn transaction_proof(&self, tx_index: u64) -> TransactionProof {
let blockchain_schema = CoreSchema::new(self.0.snapshot());
let blockchain_schema = self.0.data().for_core();
let max_height = blockchain_schema.block_hashes_by_height().len() - 1;
let latest_authorized_block = blockchain_schema
.block_and_precommits(Height(max_height))
.unwrap();

let tx_chain = self.anchoring_schema().anchoring_transactions_chain();
let tx_chain = Schema::new(self.0.service_data()).transactions_chain;

let to_table = blockchain_schema
.state_hash_aggregator()
.get_proof(IndexOwner::Service(self.0.instance.id).coordinate_for(0));
.get_proof(SchemaOrigin::Service(self.0.instance().id).coordinate_for(0));

let to_transaction = tx_chain.get_proof(tx_index);

Expand All @@ -278,20 +254,20 @@ impl<'a> PublicApi for ApiImpl<'a> {
type Error = api::Error;

fn actual_address(&self) -> Result<btc::Address, Self::Error> {
Ok(self.anchoring_schema().actual_config().anchoring_address())
Ok(Schema::new(self.0.service_data())
.actual_config()
.anchoring_address())
}

fn following_address(&self) -> Result<Option<btc::Address>, Self::Error> {
Ok(self
.anchoring_schema()
Ok(Schema::new(self.0.service_data())
.following_config()
.map(|config| config.anchoring_address()))
}

fn find_transaction(&self, height: Option<Height>) -> Result<TransactionProof, Self::Error> {
let snapshot = self.0.snapshot();
let anchoring_schema = BtcAnchoringSchema::new(self.0.instance.name, snapshot);
let tx_chain = anchoring_schema.anchoring_transactions_chain();
let anchoring_schema = Schema::new(self.0.service_data());
let tx_chain = anchoring_schema.transactions_chain;

if tx_chain.is_empty() {
return Ok(self.transaction_proof(0));
Expand Down Expand Up @@ -343,32 +319,26 @@ impl<'a> PublicApi for ApiImpl<'a> {
impl<'a> PrivateApi for ApiImpl<'a> {
type Error = api::Error;

fn sign_input(
&self,
sign_input: SignInput,
) -> Box<dyn Future<Item = Hash, Error = Self::Error>> {
fn sign_input(&self, sign_input: SignInput) -> Result<Hash, Self::Error> {
// Verify Bitcoin signature.
if let Err(e) = self.verify_sign_input(&sign_input) {
return Box::new(Err(api::Error::BadRequest(e.to_string())).into_future());
}
Box::new(self.broadcast_transaction(sign_input).map_err(From::from))
self.verify_sign_input(&sign_input)
.map_err(|e| api::Error::BadRequest(e.to_string()))?;
self.broadcast_transaction(sign_input).map_err(From::from)
}

fn add_funds(
&self,
transaction: btc::Transaction,
) -> Box<dyn Future<Item = Hash, Error = Self::Error>> {
if let Err(e) = self.verify_funding_tx(&transaction) {
return Box::new(Err(api::Error::BadRequest(e.to_string())).into_future());
}
let add_funds = AddFunds { transaction };
Box::new(self.broadcast_transaction(add_funds).map_err(From::from))
fn add_funds(&self, transaction: btc::Transaction) -> Result<Hash, Self::Error> {
self.verify_funding_tx(&transaction)
.map_err(|e| api::Error::BadRequest(e.to_string()))?;
self.broadcast_transaction(AddFunds { transaction })
.map_err(From::from)
}

fn anchoring_proposal(&self) -> Result<AnchoringProposalState, Self::Error> {
let core_schema = self.0.data().for_core();
let anchoring_schema = Schema::new(self.0.service_data());

AnchoringProposalState::try_from_proposal(
self.anchoring_schema()
.actual_proposed_anchoring_transaction(),
anchoring_schema.actual_proposed_anchoring_transaction(core_schema),
)
}

Expand All @@ -377,20 +347,16 @@ impl<'a> PrivateApi for ApiImpl<'a> {
}

fn transaction_with_index(&self, index: u64) -> Result<Option<btc::Transaction>, Self::Error> {
Ok(
BtcAnchoringSchema::new(self.0.instance.name, self.0.snapshot())
.anchoring_transactions_chain()
.get(index),
)
Ok(Schema::new(self.0.service_data())
.transactions_chain
.get(index))
}

fn transactions_count(&self) -> Result<AnchoringChainLength, Self::Error> {
Ok(
BtcAnchoringSchema::new(self.0.instance.name, self.0.snapshot())
.anchoring_transactions_chain()
.len()
.into(),
)
Ok(Schema::new(self.0.service_data())
.transactions_chain
.len()
.into())
}
}

Expand Down
Loading

0 comments on commit fdbbce9

Please sign in to comment.