Compare commits

...

8 Commits

Author SHA1 Message Date
GitLab Build Bot
ccc57328e2 js-precompiled 20170314-121823 2017-03-14 13:32:08 +01:00
arkpar
77240b6e5a Merge branch 'beta' of github.com:ethcore/parity into beta 2017-03-14 13:06:37 +01:00
Jaco Greeff
2e428ddd58 [beta] Safari fixes (#4902)
* Add intitial max-width to sections

* Move background z-index to -1
2017-03-14 13:04:08 +01:00
arkpar
cd4081c149 Additional kovan params 2017-03-14 12:04:18 +01:00
arkpar
428342d69d v1.6.3 2017-03-13 17:54:27 +01:00
arkpar
8ee9b262f9 Recalculate receipt roots in close_and_lock 2017-03-13 17:51:34 +01:00
arkpar
e2bc251ff4 v 1.6.2 2017-03-13 11:57:42 +01:00
Gav Wood
d15372c8a6 Fix auto-updater. (#4868) 2017-03-11 14:46:17 +01:00
20 changed files with 87 additions and 56 deletions

52
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root]
name = "parity"
version = "1.6.1"
version = "1.6.3"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -23,7 +23,7 @@ dependencies = [
"ethcore-secretstore 1.0.0",
"ethcore-signer 1.6.0",
"ethcore-stratum 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethsync 1.6.0",
"evmbin 0.1.0",
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -394,7 +394,7 @@ dependencies = [
"ethcore-ipc-codegen 1.6.0",
"ethcore-ipc-nano 1.6.0",
"ethcore-stratum 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethjson 0.1.0",
"ethkey 0.2.0",
"ethstore 0.1.0",
@@ -443,7 +443,7 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.6.0",
"ethcore-rpc 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"fetch 0.1.0",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
@@ -491,7 +491,7 @@ name = "ethcore-ipc"
version = "1.6.0"
dependencies = [
"ethcore-devtools 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -538,7 +538,7 @@ dependencies = [
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-ipc-nano 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -553,7 +553,7 @@ dependencies = [
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-network 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -569,7 +569,7 @@ name = "ethcore-logger"
version = "1.6.0"
dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -585,7 +585,7 @@ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.6.0",
"ethcore-io 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethcrypto 0.1.0",
"ethkey 0.2.0",
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -613,7 +613,7 @@ dependencies = [
"ethcore-io 1.6.0",
"ethcore-ipc 1.6.0",
"ethcore-light 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethcrypto 0.1.0",
"ethjson 0.1.0",
"ethkey 0.2.0",
@@ -648,7 +648,7 @@ dependencies = [
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-ipc-nano 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethcrypto 0.1.0",
"ethkey 0.2.0",
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -666,7 +666,7 @@ dependencies = [
"ethcore-devtools 1.6.0",
"ethcore-io 1.6.0",
"ethcore-rpc 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -685,7 +685,7 @@ dependencies = [
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-ipc-nano 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-macros 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
@@ -699,7 +699,7 @@ dependencies = [
[[package]]
name = "ethcore-util"
version = "1.6.1"
version = "1.6.3"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -748,7 +748,7 @@ dependencies = [
name = "ethjson"
version = "0.1.0"
dependencies = [
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -776,7 +776,7 @@ version = "0.1.0"
dependencies = [
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethcrypto 0.1.0",
"ethkey 0.2.0",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -809,7 +809,7 @@ dependencies = [
"ethcore-ipc-nano 1.6.0",
"ethcore-light 1.6.0",
"ethcore-network 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethkey 0.2.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -826,7 +826,7 @@ version = "0.1.0"
dependencies = [
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1054,7 +1054,7 @@ version = "1.6.0"
dependencies = [
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1621,7 +1621,7 @@ name = "parity-hash-fetch"
version = "1.6.0"
dependencies = [
"ethabi 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"fetch 0.1.0",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1638,7 +1638,7 @@ version = "1.6.0"
dependencies = [
"cid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
"jsonrpc-http-server 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1652,7 +1652,7 @@ version = "0.1.0"
dependencies = [
"ethcore 1.6.0",
"ethcore-io 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethkey 0.2.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0",
@@ -1675,7 +1675,7 @@ version = "1.4.0"
dependencies = [
"ethcore-rpc 1.6.0",
"ethcore-signer 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 6.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1706,7 +1706,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git?branch=beta#2a7fc4e6c5f958e8716b028b6ded010a9e238f9b"
source = "git+https://github.com/ethcore/js-precompiled.git?branch=beta#612d335a91f572cba86c1e1eed3fd2c7eb5e2b15"
dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1719,7 +1719,7 @@ dependencies = [
"ethcore 1.6.0",
"ethcore-ipc 1.6.0",
"ethcore-ipc-codegen 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"ethsync 1.6.0",
"ipc-common-types 1.6.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1993,7 +1993,7 @@ version = "1.4.0"
dependencies = [
"ethcore-bigint 0.1.2",
"ethcore-rpc 1.6.0",
"ethcore-util 1.6.1",
"ethcore-util 1.6.3",
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-rpc-client 1.4.0",
"rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,7 +1,7 @@
[package]
description = "Parity Ethereum client"
name = "parity"
version = "1.6.1"
version = "1.6.3"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]

View File

@@ -30,7 +30,8 @@
"params": {
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2A"
"networkID" : "0x2A",
"validateReceipts" : false
},
"genesis": {
"seal": {

View File

@@ -139,6 +139,7 @@
}
},
"params": {
"eip98Transition": "0x7fffffffffffffff",
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",

View File

@@ -553,7 +553,6 @@ pub fn enact(
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
b.set_uncles_hash(header.uncles_hash().clone());
b.set_transactions_root(header.transactions_root().clone());
b.set_receipts_root(header.receipts_root().clone());
push_transactions(&mut b, transactions)?;
for u in uncles {

View File

@@ -380,7 +380,7 @@ impl Client {
})?;
// Final Verification
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header(), self.engine().params().validate_receipts) {
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
}

View File

@@ -55,6 +55,8 @@ pub struct CommonParams {
pub fork_block: Option<(BlockNumber, H256)>,
/// Number of first block where EIP-98 rules begin.
pub eip98_transition: BlockNumber,
/// Validate block receipts root.
pub validate_receipts: bool,
}
impl From<ethjson::spec::Params> for CommonParams {
@@ -68,6 +70,7 @@ impl From<ethjson::spec::Params> for CommonParams {
min_gas_limit: p.min_gas_limit.into(),
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
eip98_transition: p.eip98_transition.map_or(0, Into::into),
validate_receipts: p.validate_receipts.unwrap_or(true),
}
}
}

View File

@@ -31,7 +31,7 @@ impl Verifier for CanonVerifier {
verification::verify_block_family(header, bytes, engine, bc)
}
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> {
verification::verify_block_final(expected, got)
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: bool) -> Result<(), Error> {
verification::verify_block_final(expected, got, receipts)
}
}

View File

@@ -31,7 +31,7 @@ impl Verifier for NoopVerifier {
Ok(())
}
fn verify_block_final(&self, _expected: &Header, _got: &Header) -> Result<(), Error> {
fn verify_block_final(&self, _expected: &Header, _got: &Header, _receipts: bool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -178,7 +178,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
}
/// Phase 4 verification. Check block information against transaction enactment results,
pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
pub fn verify_block_final(expected: &Header, got: &Header, check_receipts: bool) -> Result<(), Error> {
if expected.gas_used() != got.gas_used() {
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used().clone(), found: got.gas_used().clone() })))
}
@@ -188,7 +188,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
if expected.state_root() != got.state_root() {
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root().clone(), found: got.state_root().clone() })))
}
if expected.receipts_root() != got.receipts_root() {
if check_receipts && expected.receipts_root() != got.receipts_root() {
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root().clone(), found: got.receipts_root().clone() })))
}
Ok(())

View File

@@ -26,5 +26,5 @@ pub trait Verifier: Send + Sync {
/// Verify a block relative to its parent and uncles.
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
/// Do a final verification check for an enacted header vs its expected counterpart.
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error>;
fn verify_block_final(&self, expected: &Header, got: &Header, receipts: bool) -> Result<(), Error>;
}

View File

@@ -51,7 +51,7 @@ $popoverZ: 3600;
left: 0;
right: 0;
opacity: 0.25;
z-index: 0;
z-index: -1;
}
.overlay {

View File

@@ -44,6 +44,7 @@ $widthExpanded: 42%;
box-sizing: border-box;
display: flex;
flex: 0 1 $widthNormal;
max-width: $widthNormal;
opacity: 0.85;
padding: 0.25em;

View File

@@ -53,6 +53,9 @@ pub struct Params {
/// See `CommonParams` docs.
#[serde(rename="eip98Transition")]
pub eip98_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="validateReceipts")]
pub validate_receipts: Option<bool>,
}
#[cfg(test)]

View File

@@ -462,7 +462,7 @@
<key>OVERWRITE_PERMISSIONS</key>
<false/>
<key>VERSION</key>
<string>1.6.1</string>
<string>1.6.3</string>
</dict>
<key>UUID</key>
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.6</string>
<string>1.6.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>

View File

@@ -10,7 +10,7 @@
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 6
!define VERSIONBUILD 1
!define VERSIONBUILD 3
!define ARGS "--warp"
!define FIRST_START_ARGS "ui --warp --mode=passive"

View File

@@ -122,7 +122,7 @@ mod stratum;
use std::{process, env};
use std::collections::HashMap;
use std::io::{self as stdio, BufReader, Read, Write};
use std::fs::File;
use std::fs::{metadata, File};
use std::path::PathBuf;
use util::sha3::sha3;
use cli::Args;
@@ -292,8 +292,19 @@ fn main() {
let latest_exe = latest_exe_path();
let have_update = latest_exe.as_ref().map_or(false, |p| p.exists());
let is_non_updated_current = exe.as_ref().map_or(false, |exe| latest_exe.as_ref().map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok()));
trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current);
let exit_code = if have_update && is_non_updated_current {
let update_is_newer = match (
latest_exe.as_ref()
.and_then(|p| metadata(p.as_path()).ok())
.and_then(|m| m.modified().ok()),
exe.as_ref()
.and_then(|p| metadata(p.as_path()).ok())
.and_then(|m| m.modified().ok())
) {
(Some(latest_exe_time), Some(this_exe_time)) if latest_exe_time > this_exe_time => true,
_ => false,
};
trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current); trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current);
let exit_code = if have_update && is_non_updated_current && update_is_newer {
trace_main!("Attempting to run latest update ({})...", latest_exe.as_ref().expect("guarded by have_update; latest_exe must exist for have_update; qed").display());
run_parity().unwrap_or_else(|| { trace_main!("Falling back to local..."); main_direct(true) })
} else {

View File

@@ -210,13 +210,15 @@ impl Updater {
let auto = {
let mut s = self.state.lock();
let fetched = s.fetching.take().unwrap();
let b = result.map_err(|e| (format!("Unable to fetch update ({}): {:?}", fetched.version, e), false))?;
info!(target: "updater", "Fetched latest version ({}) OK to {}", fetched.version, b.display());
let dest = self.updates_path(&Self::update_file_name(&fetched.version));
fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| (format!("Unable to create updates path: {:?}", e), true))?;
fs::copy(&b, &dest).map_err(|e| (format!("Unable to copy update: {:?}", e), true))?;
restrict_permissions_owner(&dest, false, true).map_err(|e| (format!("Unable to update permissions: {}", e), true))?;
info!(target: "updater", "Installed updated binary to {}", dest.display());
if !dest.exists() {
let b = result.map_err(|e| (format!("Unable to fetch update ({}): {:?}", fetched.version, e), false))?;
info!(target: "updater", "Fetched latest version ({}) OK to {}", fetched.version, b.display());
fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| (format!("Unable to create updates path: {:?}", e), true))?;
fs::copy(&b, &dest).map_err(|e| (format!("Unable to copy update: {:?}", e), true))?;
restrict_permissions_owner(&dest, false, true).map_err(|e| (format!("Unable to update permissions: {}", e), true))?;
info!(target: "updater", "Installed updated binary to {}", dest.display());
}
let auto = match self.update_policy.filter {
UpdateFilter::All => true,
UpdateFilter::Critical if fetched.is_critical /* TODO: or is on a bad fork */ => true,
@@ -271,15 +273,23 @@ impl Updater {
let running_later = latest.track.version.version < self.version_info().version;
let running_latest = latest.track.version.hash == self.version_info().hash;
let already_have_latest = s.installed.as_ref().or(s.ready.as_ref()).map_or(false, |t| *t == latest.track);
if self.update_policy.enable_downloading && !running_later && !running_latest && !already_have_latest {
if let Some(b) = latest.track.binary {
if s.fetching.is_none() {
info!(target: "updater", "Attempting to get parity binary {}", b);
s.fetching = Some(latest.track.clone());
drop(s);
let weak_self = self.weak_self.lock().clone();
let f = move |r: Result<PathBuf, fetch::Error>| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) };
self.fetcher.lock().as_ref().expect("Created on `new`; qed").fetch(b, Box::new(f));
if self.updates_path(&Self::update_file_name(&latest.track.version)).exists() {
info!(target: "updater", "Already fetched binary.");
s.fetching = Some(latest.track.clone());
drop(s);
self.fetch_done(Ok(PathBuf::new()));
} else {
info!(target: "updater", "Attempting to get parity binary {}", b);
s.fetching = Some(latest.track.clone());
drop(s);
let weak_self = self.weak_self.lock().clone();
let f = move |r: Result<PathBuf, fetch::Error>| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) };
self.fetcher.lock().as_ref().expect("Created on `new`; qed").fetch(b, Box::new(f));
}
}
}
}
@@ -356,6 +366,8 @@ impl Service for Updater {
s.installed = Some(r);
if let Some(ref h) = *self.exit_handler.lock() {
(*h)();
} else {
info!("Update installed; ready for restart.");
}
Ok(true)
}

View File

@@ -3,7 +3,7 @@ description = "Ethcore utility library"
homepage = "http://parity.io"
license = "GPL-3.0"
name = "ethcore-util"
version = "1.6.1"
version = "1.6.3"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"