Formatting.

This commit is contained in:
Ignotus Peverell 2017-05-31 14:44:44 -07:00
parent f79fb8ef95
commit 996eab72ae
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
13 changed files with 221 additions and 207 deletions

View file

@ -28,7 +28,7 @@ use rest::Error;
pub fn get<'a, T>(url: &'a str) -> Result<T, Error>
where for<'de> T: Deserialize<'de>
{
println!("get {}", url);
println!("get {}", url);
let client = hyper::Client::new();
let res = check_error(client.get(url).send())?;
serde_json::from_reader(res)

View file

@ -72,9 +72,11 @@ impl ApiEndpoint for OutputApi {
}
fn get(&self, id: String) -> ApiResult<Output> {
debug!("GET output {}", id);
let c = util::from_hex(id.clone()).map_err(|e| Error::Argument(format!("Not a valid commitment: {}", id)))?;
self.chain_store.get_output_by_commit(&Commitment::from_vec(c)).map_err(|e| Error::Internal(e.to_string()))
debug!("GET output {}", id);
let c = util::from_hex(id.clone()).map_err(|e| Error::Argument(format!("Not a valid commitment: {}", id)))?;
self.chain_store
.get_output_by_commit(&Commitment::from_vec(c))
.map_err(|e| Error::Internal(e.to_string()))
}
}
@ -84,8 +86,10 @@ pub fn start_rest_apis(addr: String, chain_store: Arc<chain::ChainStore>) {
thread::spawn(move || {
let mut apis = ApiServer::new("/v1".to_string());
apis.register_endpoint("/chain".to_string(), ChainApi { chain_store: chain_store.clone() });
apis.register_endpoint("/chain/output".to_string(), OutputApi { chain_store: chain_store.clone() });
apis.register_endpoint("/chain".to_string(),
ChainApi { chain_store: chain_store.clone() });
apis.register_endpoint("/chain/output".to_string(),
OutputApi { chain_store: chain_store.clone() });
apis.start(&addr[..]).unwrap_or_else(|e| {
error!("Failed to start API HTTP server: {}.", e);
});

View file

@ -181,4 +181,4 @@ mod tests {
assert_eq!(tip.prev_block_h, d_tip.prev_block_h);
assert_eq!(tip.total_difficulty, d_tip.total_difficulty);
}
}
}

View file

@ -103,8 +103,8 @@ impl ChainStore for ChainKVStore {
// saving the full output under its hash, as well as a commitment to hash index
for out in &b.outputs {
let mut out_bytes = out.commit.as_ref().to_vec();
println!("OUTSAVE: {:?}", out_bytes);
let mut out_bytes = out.commit.as_ref().to_vec();
println!("OUTSAVE: {:?}", out_bytes);
batch = batch.put_enc(&mut BlockCodec::default(),
&to_key(OUTPUT_COMMIT_PREFIX, &mut out_bytes)[..],
out.hash().clone())?;
@ -125,7 +125,8 @@ impl ChainStore for ChainKVStore {
fn get_output_by_commit(&self, commit: &Commitment) -> Result<Output, Error> {
option_to_not_found(self.db.get_dec(&mut BlockCodec::default(),
&to_key(OUTPUT_COMMIT_PREFIX, &mut commit.as_ref().to_vec())))
&to_key(OUTPUT_COMMIT_PREFIX,
&mut commit.as_ref().to_vec())))
}
fn has_output_commit(&self, commit: &Commitment) -> Result<Hash, Error> {

View file

@ -46,7 +46,7 @@ pub struct BlockHeader {
pub timestamp: time::Tm,
/// Length of the cuckoo cycle used to mine this block.
pub cuckoo_len: u8,
/// Merkle root of the UTXO set
/// Merkle root of the UTXO set
pub utxo_merkle: Hash,
/// Merkle tree of hashes for all inputs, outputs and kernels in the block
pub tx_merkle: Hash,
@ -90,7 +90,7 @@ impl Writeable for BlockHeader {
[write_u8, self.cuckoo_len],
[write_fixed_bytes, &self.utxo_merkle],
[write_fixed_bytes, &self.tx_merkle],
[write_u8, self.features.bits()]);
[write_u8, self.features.bits()]);
try!(writer.write_u64(self.nonce));
try!(self.difficulty.write(writer));
@ -141,13 +141,13 @@ impl Readable for BlockHeader {
/// additive to the total of fees ever collected.
#[derive(Clone, Debug, PartialEq)]
pub struct Block {
/// The header with metadata and commitments to the rest of the data
/// The header with metadata and commitments to the rest of the data
pub header: BlockHeader,
/// List of transaction inputs
/// List of transaction inputs
pub inputs: Vec<Input>,
/// List of transaction outputs
/// List of transaction outputs
pub outputs: Vec<Output>,
/// List of transaction kernels and associated proofs
/// List of transaction kernels and associated proofs
pub kernels: Vec<TxKernel>,
}
@ -228,7 +228,6 @@ impl Default for Block {
}
impl Block {
/// Builds a new block from the header of the previous block, a vector of
/// transactions and the private key that will receive the reward. Checks
/// that all transactions are valid and calculates the Merkle tree.
@ -240,17 +239,17 @@ impl Block {
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
let (reward_out, reward_proof) = try!(Block::reward_output(reward_key, &secp));
Block::with_reward(prev, txs, reward_out, reward_proof)
Block::with_reward(prev, txs, reward_out, reward_proof)
}
/// Builds a new block ready to mine from the header of the previous block,
/// a vector of transactions and the reward information. Checks
/// a vector of transactions and the reward information. Checks
/// that all transactions are valid and calculates the Merkle tree.
pub fn with_reward(prev: &BlockHeader,
txs: Vec<&mut Transaction>,
reward_out: Output,
reward_kern: TxKernel)
-> Result<Block, secp::Error> {
txs: Vec<&mut Transaction>,
reward_out: Output,
reward_kern: TxKernel)
-> Result<Block, secp::Error> {
// note: the following reads easily but may not be the most efficient due to
// repeated iterations, revisit if a problem
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
@ -295,15 +294,15 @@ impl Block {
kernels: kernels,
}
.compact())
}
}
/// Blockhash, computed using only the header
/// Blockhash, computed using only the header
pub fn hash(&self) -> Hash {
self.header.hash()
}
/// Sum of all fees (inputs less outputs) in the block
/// Sum of all fees (inputs less outputs) in the block
pub fn total_fees(&self) -> u64 {
self.kernels.iter().map(|p| p.fee).sum()
}
@ -350,7 +349,8 @@ impl Block {
}
}
/// Merges the 2 blocks, essentially appending the inputs, outputs and kernels.
/// Merges the 2 blocks, essentially appending the inputs, outputs and
/// kernels.
/// Also performs a compaction on the result.
pub fn merge(&self, other: Block) -> Block {
let mut all_inputs = self.inputs.clone();
@ -448,10 +448,11 @@ impl Block {
.verify_kernels(secp)
}
/// Builds the blinded output and related signature proof for the block reward.
/// Builds the blinded output and related signature proof for the block
/// reward.
pub fn reward_output(skey: secp::key::SecretKey,
secp: &Secp256k1)
-> Result<(Output, TxKernel), secp::Error> {
secp: &Secp256k1)
-> Result<(Output, TxKernel), secp::Error> {
let msg = try!(secp::Message::from_slice(&[0; secp::constants::MESSAGE_SIZE]));
let sig = try!(secp.sign(&msg, &skey));
let commit = secp.commit(REWARD, skey).unwrap();

View file

@ -205,9 +205,8 @@ mod test {
#[test]
fn blind_simpler_tx() {
let secp = Secp256k1::with_caps(secp::ContextFlag::Commit);
let (tx, _) =
transaction(vec![input_rand(6), output(2, key::ONE_KEY), with_fee(4)])
.unwrap();
let (tx, _) = transaction(vec![input_rand(6), output(2, key::ONE_KEY), with_fee(4)])
.unwrap();
tx.verify_sig(&secp).unwrap();
}
}

View file

@ -48,15 +48,15 @@ impl fmt::Display for Hash {
}
impl Hash {
/// Builds a Hash from a byte vector. If the vector is too short, it will be
/// completed by zeroes. If it's too long, it will be truncated.
pub fn from_vec(v: Vec<u8>) -> Hash {
let mut h = [0; 32];
for i in 0..min(v.len(), 32) {
h[i] = v[i];
}
Hash(h)
}
/// Builds a Hash from a byte vector. If the vector is too short, it will be
/// completed by zeroes. If it's too long, it will be truncated.
pub fn from_vec(v: Vec<u8>) -> Hash {
let mut h = [0; 32];
for i in 0..min(v.len(), 32) {
h[i] = v[i];
}
Hash(h)
}
/// Converts the hash to a byte vector
pub fn to_vec(&self) -> Vec<u8> {
@ -65,49 +65,49 @@ impl Hash {
}
impl ops::Index<usize> for Hash {
type Output = u8;
type Output = u8;
fn index(&self, idx: usize) -> &u8 {
&self.0[idx]
}
fn index(&self, idx: usize) -> &u8 {
&self.0[idx]
}
}
impl ops::Index<ops::Range<usize>> for Hash {
type Output = [u8];
type Output = [u8];
fn index(&self, idx: ops::Range<usize>) -> &[u8] {
&self.0[idx]
}
fn index(&self, idx: ops::Range<usize>) -> &[u8] {
&self.0[idx]
}
}
impl ops::Index<ops::RangeTo<usize>> for Hash {
type Output = [u8];
type Output = [u8];
fn index(&self, idx: ops::RangeTo<usize>) -> &[u8] {
&self.0[idx]
}
fn index(&self, idx: ops::RangeTo<usize>) -> &[u8] {
&self.0[idx]
}
}
impl ops::Index<ops::RangeFrom<usize>> for Hash {
type Output = [u8];
type Output = [u8];
fn index(&self, idx: ops::RangeFrom<usize>) -> &[u8] {
&self.0[idx]
}
fn index(&self, idx: ops::RangeFrom<usize>) -> &[u8] {
&self.0[idx]
}
}
impl ops::Index<ops::RangeFull> for Hash {
type Output = [u8];
type Output = [u8];
fn index(&self, idx: ops::RangeFull) -> &[u8] {
&self.0[idx]
}
fn index(&self, idx: ops::RangeFull) -> &[u8] {
&self.0[idx]
}
}
impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] {
&self.0
}
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Readable for Hash {
@ -133,17 +133,19 @@ pub struct HashWriter {
}
impl HashWriter {
/// Consume the `HashWriter`, outputting its current hash into a 32-byte array
/// Consume the `HashWriter`, outputting its current hash into a 32-byte
/// array
pub fn finalize(self, output: &mut [u8]) {
self.state.finalize(output);
}
/// Consume the `HashWriter`, outputting a `Hash` corresponding to its current state
pub fn into_hash(self) -> Hash {
let mut new_hash = ZERO_HASH;
/// Consume the `HashWriter`, outputting a `Hash` corresponding to its
/// current state
pub fn into_hash(self) -> Hash {
let mut new_hash = ZERO_HASH;
self.state.finalize(&mut new_hash.0[..]);
new_hash
}
new_hash
}
}
impl Default for HashWriter {
@ -165,7 +167,7 @@ impl ser::Writer for HashWriter {
/// A trait for types that have a canonical hash
pub trait Hashed {
/// Obtain the hash of the object
/// Obtain the hash of the object
fn hash(&self) -> Hash;
}

View file

@ -33,7 +33,7 @@ pub const MAX_TARGET: [u8; 32] = [0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/// The difficulty is defined as the maximum target divided by the block hash.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Difficulty {
num: BigUint
num: BigUint,
}
impl Difficulty {
@ -44,15 +44,15 @@ impl Difficulty {
Difficulty { num: BigUint::new(vec![1]) }
}
/// Convert a `u32` into a `Difficulty`
/// Convert a `u32` into a `Difficulty`
pub fn from_num(num: u32) -> Difficulty {
Difficulty { num: BigUint::new(vec![num]) }
}
/// Convert a `BigUint` into a `Difficulty`
pub fn from_biguint(num: BigUint) -> Difficulty {
Difficulty { num: num }
}
/// Convert a `BigUint` into a `Difficulty`
pub fn from_biguint(num: BigUint) -> Difficulty {
Difficulty { num: num }
}
/// Computes the difficulty from a hash. Divides the maximum target by the
/// provided hash.
@ -62,16 +62,16 @@ impl Difficulty {
Difficulty { num: max_target / h_num }
}
/// Converts the difficulty into a bignum
pub fn into_biguint(self) -> BigUint {
self.num
}
/// Converts the difficulty into a bignum
pub fn into_biguint(self) -> BigUint {
self.num
}
}
impl fmt::Display for Difficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.num)
}
write!(f, "{}", self.num)
}
}
impl Add<Difficulty> for Difficulty {

View file

@ -55,10 +55,10 @@ pub struct TxKernel {
impl Writeable for TxKernel {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
ser_multiwrite!(writer,
[write_u8, self.features.bits()],
[write_fixed_bytes, &self.excess],
[write_bytes, &self.excess_sig],
[write_u64, self.fee]);
[write_u8, self.features.bits()],
[write_fixed_bytes, &self.excess],
[write_bytes, &self.excess_sig],
[write_u64, self.fee]);
Ok(())
}
}
@ -261,7 +261,7 @@ impl Readable for Input {
/// The input for a transaction, which spends a pre-existing output. The input
/// commitment is a reproduction of the commitment of the output it's spending.
impl Input {
/// Extracts the referenced commitment from a transaction output
/// Extracts the referenced commitment from a transaction output
pub fn commitment(&self) -> Commitment {
self.0
}
@ -286,9 +286,9 @@ bitflags! {
pub struct Output {
/// Options for an output's structure or use
pub features: OutputFeatures,
/// The homomorphic commitment representing the output's amount
/// The homomorphic commitment representing the output's amount
pub commit: Commitment,
/// A proof that the commitment is in the right range
/// A proof that the commitment is in the right range
pub proof: RangeProof,
}
@ -296,7 +296,9 @@ pub struct Output {
/// an Output as binary.
impl Writeable for Output {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
ser_multiwrite!(writer, [write_u8, self.features.bits()], [write_fixed_bytes, &self.commit]);
ser_multiwrite!(writer,
[write_u8, self.features.bits()],
[write_fixed_bytes, &self.commit]);
// The hash of an output doesn't include the range proof
if writer.serialization_mode() == ser::SerializationMode::Full {
writer.write_bytes(&self.proof)?

View file

@ -32,9 +32,9 @@ const MAXPATHLEN: usize = 8192;
/// A cuckoo-cycle related error
#[derive(Debug)]
pub enum Error {
/// Unable to find a short enough path
/// Unable to find a short enough path
Path,
/// Unable to find a solution
/// Unable to find a solution
NoSolution,
}
@ -168,7 +168,7 @@ enum CycleSol {
}
impl Miner {
/// Creates a new miner
/// Creates a new miner
pub fn new(header: &[u8], ease: u32, sizeshift: u32) -> Miner {
let cuckoo = Cuckoo::new(header, sizeshift);
let size = 1 << sizeshift;
@ -181,7 +181,7 @@ impl Miner {
}
}
/// Searches for a solution
/// Searches for a solution
pub fn mine(&mut self) -> Result<Proof, Error> {
let mut us = [0; MAXPATHLEN];
let mut vs = [0; MAXPATHLEN];

View file

@ -34,9 +34,9 @@ pub enum Error {
IOErr(io::Error),
/// Expected a given value that wasn't found
UnexpectedData {
/// What we wanted
/// What we wanted
expected: Vec<u8>,
/// What we got
/// What we got
received: Vec<u8>,
},
/// Data wasn't in a consumable format
@ -179,7 +179,9 @@ pub trait Writeable {
/// Trait that every type that can be deserialized from binary must implement.
/// Reads directly to a Reader, a utility type thinly wrapping an
/// underlying Read implementation.
pub trait Readable where Self: Sized {
pub trait Readable
where Self: Sized
{
/// Reads the data necessary to this Readable from the provided reader
fn read(reader: &mut Reader) -> Result<Self, Error>;
}
@ -326,36 +328,35 @@ impl_int!(u64, write_u64, read_u64);
impl_int!(i64, write_i64, read_i64);
impl<A: Writeable, B: Writeable> Writeable for (A, B) {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
try!(Writeable::write(&self.0, writer));
Writeable::write(&self.1, writer)
}
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
try!(Writeable::write(&self.0, writer));
Writeable::write(&self.1, writer)
}
}
impl<A: Readable, B: Readable> Readable for (A, B) {
fn read(reader: &mut Reader) -> Result<(A, B), Error> {
Ok((try!(Readable::read(reader)),
try!(Readable::read(reader))))
}
fn read(reader: &mut Reader) -> Result<(A, B), Error> {
Ok((try!(Readable::read(reader)), try!(Readable::read(reader))))
}
}
impl<A: Writeable, B: Writeable, C: Writeable> Writeable for (A, B, C) {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
try!(Writeable::write(&self.0, writer));
try!(Writeable::write(&self.1, writer));
Writeable::write(&self.2, writer)
}
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
try!(Writeable::write(&self.0, writer));
try!(Writeable::write(&self.1, writer));
Writeable::write(&self.2, writer)
}
}
impl<A: Readable, B: Readable, C: Readable> Readable for (A, B, C) {
fn read(reader: &mut Reader) -> Result<(A, B, C), Error> {
Ok((try!(Readable::read(reader)),
try!(Readable::read(reader)),
try!(Readable::read(reader))))
}
fn read(reader: &mut Reader) -> Result<(A, B, C), Error> {
Ok((try!(Readable::read(reader)),
try!(Readable::read(reader)),
try!(Readable::read(reader))))
}
}
/// Useful marker trait on types that can be sized byte slices
/// Useful marker trait on types that can be sized byte slices
pub trait AsFixedBytes: Sized + AsRef<[u8]> {}
impl<'a> AsFixedBytes for &'a [u8] {}

View file

@ -45,7 +45,7 @@ use secp::Secp256k1;
fn main() {
env_logger::init().unwrap();
let args = App::new("Grin")
let args = App::new("Grin")
.version("0.1")
.author("The Grin Team")
.about("Lightweight implementation of the MimbleWimble protocol.")
@ -109,110 +109,114 @@ fn main() {
.takes_value(true))))
.get_matches();
match args.subcommand() {
// server commands and options
("server", Some(server_args)) => {
server_command(server_args);
}
match args.subcommand() {
// server commands and options
("server", Some(server_args)) => {
server_command(server_args);
}
// client commands and options
("client", Some(client_args)) => {
match client_args.subcommand() {
("status", _) => {
println!("status info...");
},
_ => panic!("Unknown client command, use 'grin help client' for details"),
}
}
// client commands and options
("client", Some(client_args)) => {
match client_args.subcommand() {
("status", _) => {
println!("status info...");
}
_ => panic!("Unknown client command, use 'grin help client' for details"),
}
}
// client commands and options
("wallet", Some(wallet_args)) => {
wallet_command(wallet_args);
}
// client commands and options
("wallet", Some(wallet_args)) => {
wallet_command(wallet_args);
}
_ => println!("Unknown command, use 'grin help' for a list of all commands"),
}
_ => println!("Unknown command, use 'grin help' for a list of all commands"),
}
}
/// Handles the server part of the command line, mostly running, starting and
/// stopping the Grin blockchain server. Processes all the command line arguments
/// stopping the Grin blockchain server. Processes all the command line
/// arguments
/// to build a proper configuration and runs Grin with that configuration.
fn server_command(server_args: &ArgMatches) {
info!("Starting the Grin server...");
info!("Starting the Grin server...");
// configuration wrangling
let mut server_config = read_config();
if let Some(port) = server_args.value_of("port") {
server_config.p2p_config.port = port.parse().unwrap();
}
if server_args.is_present("mine") {
server_config.mining_config.enable_mining = true;
}
if let Some(seeds) = server_args.values_of("seed") {
server_config.seeding_type = grin::Seeding::List(seeds.map(|s| s.to_string()).collect());
}
// configuration wrangling
let mut server_config = read_config();
if let Some(port) = server_args.value_of("port") {
server_config.p2p_config.port = port.parse().unwrap();
}
if server_args.is_present("mine") {
server_config.mining_config.enable_mining = true;
}
if let Some(seeds) = server_args.values_of("seed") {
server_config.seeding_type = grin::Seeding::List(seeds.map(|s| s.to_string()).collect());
}
// start the server in the different run modes (interactive or daemon)
match server_args.subcommand() {
("run", _) => {
grin::Server::start(server_config).unwrap();
loop {
thread::sleep(Duration::from_secs(60));
}
},
("start", _) => {
let daemonize = Daemonize::new()
.pid_file("/tmp/grin.pid")
.chown_pid_file(true)
.privileged_action(move || {
grin::Server::start(server_config.clone()).unwrap();
loop {
thread::sleep(Duration::from_secs(60));
}
});
match daemonize.start() {
Ok(_) => info!("Grin server succesfully started."),
Err(e) => error!("Error starting: {}", e),
}
}
("stop", _) => {
println!("TODO, just 'kill $pid' for now.")
}
_ => panic!("Unknown server command, use 'grin help server' for details"),
}
// start the server in the different run modes (interactive or daemon)
match server_args.subcommand() {
("run", _) => {
grin::Server::start(server_config).unwrap();
loop {
thread::sleep(Duration::from_secs(60));
}
}
("start", _) => {
let daemonize = Daemonize::new()
.pid_file("/tmp/grin.pid")
.chown_pid_file(true)
.privileged_action(move || {
grin::Server::start(server_config.clone()).unwrap();
loop {
thread::sleep(Duration::from_secs(60));
}
});
match daemonize.start() {
Ok(_) => info!("Grin server succesfully started."),
Err(e) => error!("Error starting: {}", e),
}
}
("stop", _) => println!("TODO, just 'kill $pid' for now."),
_ => panic!("Unknown server command, use 'grin help server' for details"),
}
}
fn wallet_command(wallet_args: &ArgMatches) {
let hd_seed = wallet_args.value_of("pass").expect("Wallet passphrase required.");
let hd_seed = wallet_args.value_of("pass").expect("Wallet passphrase required.");
// TODO do something closer to BIP39, eazy solution right now
let mut sha3 = Keccak::new_sha3_256();
sha3.update(hd_seed.as_bytes());
let mut seed = [0; 32];
sha3.finalize(&mut seed);
// TODO do something closer to BIP39, eazy solution right now
let mut sha3 = Keccak::new_sha3_256();
sha3.update(hd_seed.as_bytes());
let mut seed = [0; 32];
sha3.finalize(&mut seed);
let s = Secp256k1::new();
let key = wallet::ExtendedKey::from_seed(&s, &seed[..]).expect("Error deriving extended key from seed.");
let key = wallet::ExtendedKey::from_seed(&s, &seed[..])
.expect("Error deriving extended key from seed.");
match wallet_args.subcommand() {
("receive", _) => {
info!("Starting the Grin wallet receiving daemon...");
let mut apis = api::ApiServer::new("/v1".to_string());
apis.register_endpoint("/receive_coinbase".to_string(), wallet::WalletReceiver { key: key });
apis.start("127.0.0.1:13416").unwrap_or_else(|e| {
error!("Failed to start Grin wallet receiver: {}.", e);
});
}
("send", Some(send_args)) => {
let amount = send_args.value_of("amount").expect("Amount to send required").parse().expect("Could not parse amount as a whole number.");
let mut dest = "stdout";
if let Some(d) = send_args.value_of("dest") {
dest = d;
}
wallet::issue_send_tx(&key, amount, dest.to_string()).unwrap();
}
_ => panic!("Unknown wallet command, use 'grin help wallet' for details"),
}
match wallet_args.subcommand() {
("receive", _) => {
info!("Starting the Grin wallet receiving daemon...");
let mut apis = api::ApiServer::new("/v1".to_string());
apis.register_endpoint("/receive_coinbase".to_string(),
wallet::WalletReceiver { key: key });
apis.start("127.0.0.1:13416").unwrap_or_else(|e| {
error!("Failed to start Grin wallet receiver: {}.", e);
});
}
("send", Some(send_args)) => {
let amount = send_args.value_of("amount")
.expect("Amount to send required")
.parse()
.expect("Could not parse amount as a whole number.");
let mut dest = "stdout";
if let Some(d) = send_args.value_of("dest") {
dest = d;
}
wallet::issue_send_tx(&key, amount, dest.to_string()).unwrap();
}
_ => panic!("Unknown wallet command, use 'grin help wallet' for details"),
}
}
fn read_config() -> grin::ServerConfig {

View file

@ -22,7 +22,7 @@ use extkey::ExtendedKey;
use types::*;
pub fn issue_send_tx(ext_key: &ExtendedKey, amount: u64, dest: String) -> Result<(), Error> {
checker::refresh_outputs(&WalletConfig::default(), ext_key);
checker::refresh_outputs(&WalletConfig::default(), ext_key);
let (tx, blind_sum) = build_send_tx(ext_key, amount)?;
let json_tx = partial_tx_to_json(amount, blind_sum, tx);