├── .gitmodules ├── proto ├── src │ ├── google.protobuf.rs │ ├── proto.discovery.rs │ ├── proto.channel.rs │ └── contract_ext.rs ├── Cargo.toml ├── README.md ├── proto │ ├── discovery.proto │ ├── channel.proto │ └── common.proto └── build.rs ├── types ├── src │ └── lib.rs ├── README.md └── Cargo.toml ├── services ├── channel │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── discovery │ ├── src │ │ ├── lib.rs │ │ └── peer.rs │ └── Cargo.toml ├── graphql │ ├── src │ │ ├── lib.rs │ │ ├── model.rs │ │ ├── server.rs │ │ └── scalar.rs │ └── Cargo.toml └── producer │ └── Cargo.toml ├── ztron ├── src │ ├── lib.rs │ └── precompiles │ │ └── helper.rs ├── Cargo.toml └── tests │ ├── burn.hex │ ├── precompiles.rs │ ├── mint.hex │ ├── transfer.hex │ └── transfer.to2.hex ├── tvm ├── src │ ├── backend.rs │ ├── lib.rs │ └── precompile │ │ ├── helper.rs │ │ ├── alt_bn128.rs │ │ └── tron.rs └── Cargo.toml ├── assets ├── logo-small.png └── logo-medium.png ├── opentron ├── src │ ├── commands │ │ ├── mod.rs │ │ ├── fix.rs │ │ ├── dev.rs │ │ ├── check.rs │ │ └── key.rs │ ├── lib.rs │ ├── util.rs │ ├── cli.yml │ └── main.rs ├── README.md └── Cargo.toml ├── merkle-tree ├── README.md ├── Cargo.toml └── src │ ├── lib.rs │ ├── merkle_tree.rs │ └── tree.rs ├── manager ├── src │ ├── governance │ │ └── mod.rs │ ├── version_fork.rs │ └── executor │ │ └── actuators │ │ ├── shielded.rs │ │ └── transfer.rs └── Cargo.toml ├── constants ├── Cargo.toml └── src │ ├── lib.rs │ └── block_version.rs ├── state ├── src │ ├── lib.rs │ ├── parameter.rs │ └── property.rs └── Cargo.toml ├── .clang-format ├── .cargo └── config ├── .gitignore ├── crypto ├── Cargo.toml └── src │ └── lib.rs ├── rustfmt.toml ├── keys ├── Cargo.toml └── src │ ├── lib.rs │ ├── error.rs │ ├── keypair.rs │ ├── private.rs │ └── signature.rs ├── scripts └── download-ztron-params.sh ├── config ├── Cargo.toml └── src │ └── genesis.rs ├── chain ├── src │ ├── lib.rs │ ├── merkle_root.rs │ ├── block_builder.rs │ ├── indexed_transaction.rs │ └── indexed_header.rs └── Cargo.toml ├── chain-db └── Cargo.toml ├── cli ├── src │ ├── util.rs │ ├── witness.rs │ ├── account.rs │ ├── proposal.rs │ ├── system.rs │ └── main.rs └── Cargo.toml ├── .editorconfig ├── context ├── Cargo.toml └── src │ └── lib.rs ├── Cargo.toml ├── etc ├── genesis.local-test.json ├── conf.nile.toml ├── conf.local-test.toml ├── conf.toml ├── genesis.json └── genesis.nile.json ├── LICENSE-MIT ├── docs ├── graphql.md ├── txpool.md ├── tvm.md ├── proposal.md ├── versions.md └── networks.md ├── .github └── workflows │ └── rust.yml └── INSTALL.md /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /proto/src/google.protobuf.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /types/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use primitive_types::*; 2 | -------------------------------------------------------------------------------- /services/channel/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod protocol; 2 | pub mod server; 3 | -------------------------------------------------------------------------------- /ztron/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod builder; 2 | pub mod keys; 3 | pub mod precompiles; 4 | -------------------------------------------------------------------------------- /services/discovery/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod peer; 2 | pub mod protocol; 3 | pub mod server; 4 | -------------------------------------------------------------------------------- /tvm/src/backend.rs: -------------------------------------------------------------------------------- 1 | pub use evm::backend::{Apply, ApplyBackend, Backend, Basic, Log}; 2 | -------------------------------------------------------------------------------- /types/README.md: -------------------------------------------------------------------------------- 1 | # types 2 | 3 | This reexports all types from `primitive-types`. 4 | -------------------------------------------------------------------------------- /assets/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andelf/opentron/HEAD/assets/logo-small.png -------------------------------------------------------------------------------- /assets/logo-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andelf/opentron/HEAD/assets/logo-medium.png -------------------------------------------------------------------------------- /opentron/src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod check; 2 | pub mod dev; 3 | pub mod fix; 4 | pub mod key; 5 | -------------------------------------------------------------------------------- /opentron/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "2048"] 2 | 3 | pub mod commands; 4 | pub mod util; 5 | -------------------------------------------------------------------------------- /merkle-tree/README.md: -------------------------------------------------------------------------------- 1 | # merkle-tree 2 | 3 | Code borrowed from . 4 | -------------------------------------------------------------------------------- /services/graphql/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod contract; 2 | pub mod model; 3 | pub mod scalar; 4 | pub mod schema; 5 | pub mod server; 6 | -------------------------------------------------------------------------------- /manager/src/governance/mod.rs: -------------------------------------------------------------------------------- 1 | //! Chain governance related. 2 | 3 | pub mod maintenance; 4 | pub mod proposal; 5 | pub mod reward; 6 | -------------------------------------------------------------------------------- /constants/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "constants" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | -------------------------------------------------------------------------------- /state/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use parameter::ChainParameter; 2 | pub use property::DynamicProperty; 3 | 4 | pub mod db; 5 | pub mod keys; 6 | pub mod parameter; 7 | mod property; 8 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | ColumnLimit: 120 4 | UseTab: Never 5 | --- 6 | Language: Proto 7 | BasedOnStyle: Google 8 | ColumnLimit: 120 9 | # IndentWidth: 2 10 | -------------------------------------------------------------------------------- /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | rustflags = [ 3 | # "-C", "link-arg=-fuse-ld=lld", 4 | "-C", "link-arg=-L/usr/local/lib", 5 | ] 6 | 7 | # [build] 8 | # target = "x86_64-unknown-linux-gnu" 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/ztron-params 3 | backup/ 4 | data/ 5 | data.*/ 6 | 7 | peers.json 8 | 9 | # backup files 10 | trash/ 11 | trash.* 12 | *._rc 13 | 14 | # misc 15 | .DS_Store 16 | .vscode/ 17 | *.log 18 | -------------------------------------------------------------------------------- /opentron/README.md: -------------------------------------------------------------------------------- 1 | # opentron 2 | 3 | The OpenTron client implementation. 4 | 5 | ```console 6 | > cargo run -p opentron -- --config ./config/conf.nile.toml run 7 | Now a local block store is created and started syncing. 8 | ``` 9 | -------------------------------------------------------------------------------- /crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crypto" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sha2 = "0.9" 9 | sha3 = "0.9" 10 | digest = "0.9" 11 | types = { path = "../types" } 12 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 120 2 | comment_width=120 3 | # fn_call_width=100 4 | reorder_imports = true 5 | binop_separator = "Back" 6 | edition = "2018" 7 | newline_style = "Unix" 8 | normalize_comments = false 9 | # trailing_comma = "Never" 10 | tab_spaces = 4 11 | -------------------------------------------------------------------------------- /types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "types" 3 | description = "OpenTron primitive types" 4 | version = "0.1.0" 5 | authors = ["OpenTron Developers "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | primitive-types = { version = "0.8", features = [], default-features = false } 10 | -------------------------------------------------------------------------------- /keys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "keys" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | base58 = "0.2" 9 | hex = "0.4" 10 | sha2 = "0.9" 11 | sha3 = "0.9" 12 | digest = "0.9" 13 | libsecp256k1 = "0.7" 14 | # locked with libsecp256k1 15 | rand = "0.8" 16 | -------------------------------------------------------------------------------- /scripts/download-ztron-params.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | mkdir -p ztron-params 6 | cd ztron-params 7 | wget -c https://github.com/tronprotocol/java-tron/raw/master/framework/src/main/resources/params/sapling-output.params 8 | wget -c https://github.com/tronprotocol/java-tron/raw/master/framework/src/main/resources/params/sapling-spend.params 9 | -------------------------------------------------------------------------------- /merkle-tree/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "merkle-tree" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | types = { path = "../types" } 11 | 12 | [dev-dependencies] 13 | sha2 = "0.9" 14 | -------------------------------------------------------------------------------- /keys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Tron Protocol Keys 2 | 3 | #![deny(missing_docs)] 4 | 5 | mod address; 6 | mod error; 7 | mod keypair; 8 | mod private; 9 | mod public; 10 | mod signature; 11 | 12 | pub use address::{b58decode_check, b58encode_check, Address}; 13 | pub use error::Error; 14 | pub use keypair::KeyPair; 15 | pub use private::Private; 16 | pub use public::Public; 17 | pub use signature::Signature; 18 | -------------------------------------------------------------------------------- /config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "config" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = { version = "1.0", features = ["derive"] } 9 | serde_json = "1.0" 10 | prost = "0.8" 11 | hex = "0.4" 12 | toml = "0.5" 13 | 14 | chain = { path = "../chain" } 15 | keys = { path = "../keys" } 16 | proto = { path = "../proto" } 17 | -------------------------------------------------------------------------------- /chain/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use proto::chain::{Block, BlockHeader, Transaction}; 2 | pub use types::H256; 3 | 4 | pub use block_builder::BlockBuilder; 5 | pub use indexed_block::IndexedBlock; 6 | pub use indexed_header::IndexedBlockHeader; 7 | pub use indexed_transaction::IndexedTransaction; 8 | 9 | mod block_builder; 10 | mod indexed_block; 11 | mod indexed_header; 12 | mod indexed_transaction; 13 | mod merkle_root; 14 | -------------------------------------------------------------------------------- /proto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proto" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bytes = "1" 9 | prost = "0.8" 10 | # google.Any 11 | prost-types = "0.8" 12 | hex = "0.4" 13 | byteorder = "1.4" 14 | serde = { version = "1.0", features = ["derive"] } 15 | 16 | [build-dependencies] 17 | prost-build = "0.8" 18 | 19 | [lib] 20 | doctest = false 21 | -------------------------------------------------------------------------------- /chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chain" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | prost = "0.8" 9 | byteorder = "1.3" 10 | sha2 = "0.9" 11 | rayon = "1.5" 12 | 13 | types = { path = "../types" } 14 | proto = { path = "../proto" } 15 | crypto = { path = "../crypto" } 16 | merkle-tree = { path = "../merkle-tree" } 17 | keys = { path = "../keys" } 18 | -------------------------------------------------------------------------------- /opentron/src/util.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{ByteOrder, BE}; 2 | use serde::Deserialize; 3 | use std::error::Error; 4 | 5 | #[derive(Deserialize)] 6 | struct Ip { 7 | origin: String, 8 | } 9 | 10 | pub fn get_my_ip() -> Result> { 11 | let ip = reqwest::blocking::get("http://httpbin.org/ip")?.json::()?; 12 | Ok(ip.origin) 13 | } 14 | 15 | pub fn block_hash_to_number(hash: &[u8]) -> i64 { 16 | BE::read_u64(&hash[..8]) as _ 17 | } 18 | -------------------------------------------------------------------------------- /chain-db/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["OpenTron Developers "] 3 | edition = "2018" 4 | name = "chain-db" 5 | version = "0.1.0" 6 | 7 | [features] 8 | default = [] 9 | static-rocksdb = ["rocks/static-link"] 10 | 11 | [dependencies] 12 | byteorder = "1" 13 | bytes = "1" 14 | hex = "0.4" 15 | log = "0.4" 16 | num_cpus = "1" 17 | prost = "0.8" 18 | rand = "0.8" 19 | rocks = "0.1.10" 20 | 21 | chain = {path = "../chain"} 22 | proto = {path = "../proto"} 23 | types = {path = "../types"} 24 | -------------------------------------------------------------------------------- /proto/README.md: -------------------------------------------------------------------------------- 1 | # proto 2 | 3 | Refactored version of core protobuf files. 4 | 5 | ## Key points 6 | 7 | - Each file is in its own scope 8 | - `chain.proto`: data on the "real blockchain", blocks and transactions 9 | - `discovery.proto`: peer discovery protocol of udp/18888 10 | - `channel.proto`: sync and relay protocol of tcp/18888 11 | - `contract.proto`: all system contracts 12 | - `state.proto`: the state-db part 13 | - Handle "unknown fields" via `oneof` 14 | - a desgin fault, and is still vulnerable now 15 | -------------------------------------------------------------------------------- /cli/src/util.rs: -------------------------------------------------------------------------------- 1 | pub fn parse_amount_with_currency(amount: &str, symbol: &str, precision: u32) -> Option { 2 | if amount.ends_with(symbol) { 3 | amount 4 | .replace(symbol, "") 5 | .replace("_", "") 6 | .parse::() 7 | .ok() 8 | .map(|num| num * (10_i64.pow(precision))) 9 | } else { 10 | amount.replace("_", "").parse().ok() 11 | } 12 | } 13 | 14 | pub fn parse_amount(amount: &str) -> Option { 15 | amount.replace("_", "").parse().ok() 16 | } 17 | -------------------------------------------------------------------------------- /state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "state" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [features] 8 | default = [] 9 | static-rocksdb = ["rocks/static-link"] 10 | 11 | [dependencies] 12 | log = "0.4" 13 | byteorder = "1.4" 14 | bytes = "1" 15 | prost = "0.8" 16 | num_cpus = "1" 17 | rocks = "0.1.10" 18 | 19 | types = { path = "../types" } 20 | keys = { path = "../keys" } 21 | proto = { path = "../proto" } 22 | config = { path = "../config" } 23 | constants = { path = "../constants" } 24 | -------------------------------------------------------------------------------- /tvm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tvm" 3 | version = "4.0.1" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | libsecp256k1 = "0.7" 10 | sha3 = "0.9" 11 | sha2 = "0.9" 12 | digest = "0.9" 13 | bn-plus = "0.4" 14 | hex = "0.4" 15 | num-bigint = "0.4" 16 | num-traits = "0.2" 17 | lazy_static = "1" 18 | 19 | types = { path = "../types" } 20 | # evm = { path = "../../evm" } 21 | evm = { git = "https://github.com/opentron/evm", branch = "tron" } 22 | ztron = { path = "../ztron" } 23 | -------------------------------------------------------------------------------- /crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | use digest::Digest; 2 | use sha2::Sha256; 3 | use sha3::Keccak256; 4 | use types::H256; 5 | 6 | #[inline] 7 | pub fn sha256(input: &[u8]) -> H256 { 8 | let mut hasher = Sha256::new(); 9 | hasher.update(input); 10 | let inner: [u8; 32] = hasher.finalize().into(); 11 | H256::from(inner) 12 | } 13 | 14 | #[inline] 15 | pub fn keccak256(input: &[u8]) -> H256 { 16 | let mut hasher = Keccak256::new(); 17 | hasher.update(input); 18 | let inner: [u8; 32] = hasher.finalize().into(); 19 | H256::from(inner) 20 | } 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=space 4 | indent_size=4 5 | tab_width=4 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=120 10 | insert_final_newline=true 11 | 12 | [*.yml] 13 | indent_style=space 14 | indent_size=4 15 | tab_width=8 16 | end_of_line=lf 17 | 18 | [*.proto] 19 | indent_style=space 20 | indent_size=2 21 | max_line_length=120 22 | 23 | [*.md] 24 | indent_size = 2 25 | 26 | [*.json] 27 | indent_size = 2 28 | 29 | [*.proto] 30 | indent_size = 2 31 | 32 | [*.graphql] 33 | indent_size = 2 34 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cli" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | prost = "0.8" 10 | hex = "0.4" 11 | clap = { version = "2.33", features = ["yaml"] } 12 | chrono = "0.4" 13 | reqwest = { version = "0.11", default-features = false, features = ["blocking", "json"] } 14 | serde_json = "1.0" 15 | itertools = "0.10" 16 | 17 | proto = { path = "../proto" } 18 | keys = { path = "../keys" } 19 | crypto = { path = "../crypto" } 20 | -------------------------------------------------------------------------------- /context/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "context" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [features] 8 | default = [] 9 | javatron = ["manager/javatron"] 10 | static-rocksdb = ["manager/static-rocksdb", "chain-db/static-rocksdb"] 11 | 12 | [dependencies] 13 | log = "0.4" 14 | hex = "0.4" 15 | tokio = "1" 16 | # workspace 17 | types = { path = "../types" } 18 | config = { path = "../config" } 19 | chain = { path = "../chain" } 20 | chain-db = { path = "../chain-db" } 21 | proto = { path = "../proto" } 22 | manager = { path = "../manager" } 23 | -------------------------------------------------------------------------------- /services/discovery/src/peer.rs: -------------------------------------------------------------------------------- 1 | use proto::common::Endpoint; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Hash, Serialize, Deserialize, PartialEq, Eq)] 5 | pub struct Peer { 6 | pub id: String, 7 | pub version: i32, 8 | pub advertised_ip: String, 9 | pub advertised_port: u16, 10 | pub received_ip: String, 11 | pub received_port: u16, 12 | } 13 | 14 | impl From<&Peer> for Endpoint { 15 | fn from(peer: &Peer) -> Endpoint { 16 | Endpoint { 17 | address: peer.advertised_ip.clone(), 18 | port: peer.advertised_port as _, 19 | node_id: hex::decode(&peer.id).unwrap(), 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /services/discovery/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "discovery-service" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | description = "The discovery protocol" 8 | 9 | [dependencies] 10 | bytes = "1" 11 | futures = "0.3" 12 | tokio = { version = "1", default-features = false, features = ["net"] } 13 | tokio-stream = "0.1" 14 | prost = "0.8" 15 | chrono = "0.4" 16 | rand = "0.8" 17 | log = "0.4" 18 | hex = "0.4" 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | # workspace 22 | proto = { path = "../../proto" } 23 | config = { path = "../../config" } 24 | context = { path = "../../context" } 25 | -------------------------------------------------------------------------------- /services/channel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "channel-service" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bytes = "1" 9 | byteorder = "1" 10 | prost = "0.8" 11 | log = "0.4" 12 | slog = "2" 13 | slog-scope = "4.4" 14 | slog-scope-futures = "0.1" 15 | futures = "0.3" 16 | chrono = "0.4" 17 | tokio = { version = "1", default-features = false, features = ["macros", "net", "time"] } 18 | tokio-util = { version = "0.6", features = ["codec"] } 19 | tokio-stream = "0.1" 20 | hex = "0.4" 21 | # workspace 22 | types = { path = "../../types" } 23 | proto = { path = "../../proto" } 24 | chain = { path = "../../chain" } 25 | keys = { path = "../../keys" } 26 | context = { path = "../../context" } 27 | -------------------------------------------------------------------------------- /manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "manager" 3 | authors = ["OpenTron Developers "] 4 | edition = "2018" 5 | version = "0.1.0" 6 | 7 | [features] 8 | default = [] 9 | 10 | javatron = [] 11 | static-rocksdb = ["state/static-rocksdb"] 12 | 13 | [dependencies] 14 | chrono = "0.4" 15 | hex = "0.4" 16 | log = "0.4" 17 | prost = "0.8" 18 | lazy_static = "1.4" 19 | sha3 = "0.9" 20 | 21 | # workspace 22 | types = { path = "../types" } 23 | chain = { path = "../chain" } 24 | config = { path = "../config" } 25 | chain-db = { path = "../chain-db" } 26 | constants = { path = "../constants" } 27 | crypto = { path = "../crypto" } 28 | keys = { path = "../keys" } 29 | proto = { path = "../proto" } 30 | state = { path = "../state" } 31 | tvm = { path = "../tvm" } 32 | -------------------------------------------------------------------------------- /proto/proto/discovery.proto: -------------------------------------------------------------------------------- 1 | // Protobuf for the node discovery protocol. 2 | syntax = "proto3"; 3 | 4 | package proto.discovery; 5 | 6 | import "common.proto"; 7 | 8 | message Ping { 9 | proto.common.Endpoint from = 1; 10 | proto.common.Endpoint to = 2; 11 | int32 version = 3; 12 | int64 timestamp = 4; 13 | } 14 | 15 | message Pong { 16 | proto.common.Endpoint from = 1; 17 | int32 echo_version = 2; 18 | int64 timestamp = 3; 19 | } 20 | 21 | // renamed: FindNeighbours 22 | message FindPeers { 23 | proto.common.Endpoint from = 1; 24 | bytes target_id = 2; 25 | int64 timestamp = 3; 26 | } 27 | 28 | // renamed: Neighbours 29 | message Peers { 30 | proto.common.Endpoint from = 1; 31 | repeated proto.common.Endpoint peers = 2; 32 | int64 timestamp = 3; 33 | } 34 | -------------------------------------------------------------------------------- /proto/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | const PROTOS: &[&str] = &[ 3 | "proto/common.proto", 4 | "proto/discovery.proto", 5 | "proto/chain.proto", 6 | "proto/channel.proto", 7 | "proto/contract.proto", 8 | "proto/state.proto", 9 | ]; 10 | 11 | for f in PROTOS { 12 | println!("cargo:rerun-if-changed={}", f); 13 | } 14 | prost_build::Config::new() 15 | .type_attribute("proto.common.SmartContract.ABI", "#[derive(serde::Serialize)]") 16 | .type_attribute("proto.common.SmartContract.ABI.Entry", "#[derive(serde::Serialize)]") 17 | .type_attribute("proto.common.SmartContract.ABI.Param", "#[derive(serde::Serialize)]") 18 | .out_dir("src") 19 | .compile_protos(PROTOS, &["proto/"]) 20 | .unwrap(); 21 | } 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["opentron", "cli"] 3 | default-members = ["opentron"] 4 | 5 | 6 | [patch.crates-io] 7 | # In development. 8 | halo2 = { git = "https://github.com/zcash/halo2.git", rev = "27c4187673a9c6ade13fbdbd4f20955530c22d7f" } 9 | orchard = { git = "https://github.com/zcash/orchard.git", rev = "d0baa18fc6105df4a7847de2b6dc50c5919b3123" } 10 | incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree.git", rev = "b7bd6246122a6e9ace8edb51553fbf5228906cbb" } 11 | # zcash_encoding = { path = "components/zcash_encoding" } 12 | zcash_note_encryption = { git = "https://github.com/opentron/librustzcash.git", rev = "765645844dc6615aec2c34d83232c59fc1953662" } 13 | 14 | # Unreleased 15 | jubjub = { git = "https://github.com/zkcrypto/jubjub.git", rev = "96ab4162b83303378eae32a326b54d88b75bffc2" } 16 | -------------------------------------------------------------------------------- /chain/src/merkle_root.rs: -------------------------------------------------------------------------------- 1 | use sha2::{Digest, Sha256}; 2 | use std::mem; 3 | use types::H256; 4 | 5 | pub enum HashedSha256Hasher {} 6 | 7 | impl ::merkle_tree::MerkleHasher for HashedSha256Hasher { 8 | // FIXME: don't know how to impl for &Transaction 9 | type Input = H256; 10 | 11 | fn hash(input: &H256) -> H256 { 12 | /* 13 | let mut sha256 = Sha256::new(); 14 | sha256.input(&input.write_to_bytes().unwrap()); 15 | unsafe { mem::transmute(sha256.result()) } 16 | */ 17 | *input 18 | } 19 | 20 | fn hash_nodes(left: &H256, right: &H256) -> H256 { 21 | let result = Sha256::new().chain(left.as_bytes()).chain(right.as_bytes()).finalize(); 22 | unsafe { mem::transmute(result) } 23 | } 24 | } 25 | 26 | pub type MerkleTree = ::merkle_tree::MerkleTree; 27 | -------------------------------------------------------------------------------- /opentron/src/commands/fix.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use log::info; 3 | 4 | use context::AppContext; 5 | 6 | pub async fn main(ctx: AppContext, matches: &ArgMatches<'_>) -> Result<(), Box> { 7 | let ref db = ctx.chain_db; 8 | 9 | db.await_background_jobs(); 10 | 11 | if let Some(val) = matches.value_of("height") { 12 | info!("original block height => {}", db.get_block_height()); 13 | let new_height = val.parse().expect("height number"); 14 | db.force_update_block_height(new_height)?; 15 | info!("force update block height => {}", new_height); 16 | } 17 | 18 | if let Some(val) = matches.value_of("fork") { 19 | let block_number = val.parse().expect("height number"); 20 | db.handle_chain_fork_at(block_number, /* dry_run */ false)?; 21 | } 22 | 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /opentron/src/commands/dev.rs: -------------------------------------------------------------------------------- 1 | use chrono::Utc; 2 | use log::info; 3 | 4 | use context::AppContext; 5 | 6 | pub async fn main(ctx: AppContext) -> Result<(), Box> { 7 | let mut manager = ctx.manager.write().unwrap(); 8 | 9 | let mut start_time = Utc::now().timestamp_millis(); 10 | let mut n_blocks = 0; 11 | 12 | let start_block = manager.latest_block_number() as u64 + 1; 13 | 14 | for i in start_block.. { 15 | let blk = ctx.chain_db.get_block_by_number(i)?; 16 | 17 | manager.push_incoming_block(&blk)?; 18 | 19 | n_blocks += 1; 20 | 21 | if n_blocks % 1_000 == 0 { 22 | let now = Utc::now().timestamp_millis(); 23 | info!("speed => {}blocks/s", 1_000 * 1_000 / (now - start_time)); 24 | start_time = Utc::now().timestamp_millis(); 25 | } 26 | } 27 | 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /services/producer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "producer-service" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bytes = "1" 9 | byteorder = "1" 10 | prost = "0.8" 11 | log = "0.4" 12 | slog = "2" 13 | slog-scope = "4.4" 14 | slog-scope-futures = "0.1" 15 | futures = "0.3" 16 | chrono = "0.4" 17 | tokio = { version = "1", default-features = false, features = ["macros", "net", "time"] } 18 | tokio-util = { version = "0.6", features = ["codec"] } 19 | tokio-stream = "0.1" 20 | hex = "0.4" 21 | indexmap = "1" 22 | # workspace 23 | types = { path = "../../types" } 24 | proto = { path = "../../proto" } 25 | chain = { path = "../../chain" } 26 | keys = { path = "../../keys" } 27 | context = { path = "../../context" } 28 | config = { path = "../../config" } 29 | constants = { path = "../../constants" } 30 | manager = { path = "../../manager" } 31 | -------------------------------------------------------------------------------- /etc/genesis.local-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": 0, 3 | "parentHash": "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f", 4 | "witnesses": [ 5 | { 6 | "address": "TPBMeAqZd5JfbomoMX8BPMttSyHx4Notrx", 7 | "url": "http://GR1.com", 8 | "votes": 100000000 9 | } 10 | ], 11 | "allocs": [ 12 | { 13 | "name": "InitialAccount1", 14 | "address": "TJrsCAaTePcnB2UWkqA53nF2dnyVovotrx", 15 | "balance": 99000000000000000 16 | }, 17 | { 18 | "name": "Sun", 19 | "address": "TKXt7gXRSQ88FZBs6eXSzTCbPdFuoFg18L", 20 | "balance": 0 21 | }, 22 | { 23 | "name": "Blackhole", 24 | "address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", 25 | "balance": -9223372036854775808 26 | } 27 | ], 28 | "mantra": "A new system must allow existing systems to be linked together without requiring any central control or coordination", 29 | "creator": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb" 30 | } 31 | -------------------------------------------------------------------------------- /ztron/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ztron" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rand = "0.8" 9 | bech32 = "0.8" 10 | hex = "0.4" 11 | sha2 = "0.9" 12 | lazy_static = "1.4" 13 | ethabi = "13" 14 | crypto_api_chachapoly = "0.4" 15 | 16 | types = { path = "../types" } 17 | keys = { path = "../keys" } 18 | 19 | zcash_primitives = { git = "https://github.com/opentron/librustzcash", branch = "tron" } 20 | zcash_proofs = { git = "https://github.com/opentron/librustzcash", branch = "tron" } 21 | zcash_note_encryption = { git = "https://github.com/opentron/librustzcash", branch = "tron" } 22 | bls12_381 = "0.5" 23 | jubjub = "0.7" 24 | ff = "0.10" 25 | group = "0.10" 26 | bellman = { version = "0.10", default-features = false, features = ["groth16"] } 27 | 28 | # For Local Devs: 29 | # zcash_primitives = { path = "../../librustzcash/zcash_primitives" } 30 | # zcash_proofs = { path = "../../librustzcash/zcash_proofs" } 31 | -------------------------------------------------------------------------------- /opentron/src/commands/check.rs: -------------------------------------------------------------------------------- 1 | use chain_db::CheckResult; 2 | use clap::ArgMatches; 3 | use log::info; 4 | 5 | use context::AppContext; 6 | 7 | pub async fn main(ctx: AppContext, matches: &ArgMatches<'_>) -> Result<(), Box> { 8 | let ref db = ctx.chain_db; 9 | 10 | db.await_background_jobs(); 11 | 12 | match matches.value_of("WHAT") { 13 | Some("compact") => { 14 | println!("compact db ..."); 15 | let ret = db.compact_db(); 16 | println!("compact => {:?}", ret); 17 | } 18 | Some("merkle_tree") => { 19 | db.verify_merkle_tree(&Default::default())?; 20 | } 21 | Some("parent_hash") => { 22 | while let CheckResult::ForkAt(pos) = db.verify_parent_hashes()? { 23 | db.handle_chain_fork_at(pos, /* dry_run */ false)?; 24 | } 25 | } 26 | _ => (), 27 | } 28 | 29 | info!("block height = {}", db.get_block_height()); 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /ztron/tests/burn.hex: -------------------------------------------------------------------------------- 1 | ac206a8412ae10ec863553b865778a80efebb3229cbef81c0029b24e686c1fa4ad16aa8f5b371788c098e1273ffaba1d88a08fcb1ed17d592026560d6370e950081c27aaa835b6579df2f9ef512d2150e3733bedc85b03e54e6f8ac43547a05c1d910a528b118af7ee6ccfd6db710cd345c55ac5bec994845f0e5d6ed81fe498a5ba0b2fcd9ab8f322c22c0dedeaf6294814edd43dc9c1c1eced6a074f3bc888b4162b9b6d70499a74d9375f33458a73a74a4a314c36df3078fe5042219afa22a6b7719a0de01e1124b2c76c9d836c50f841c2d2837b8497ce4412f3cbaff3550e8cc74678269494545c25c45d2dbb0b2ce2f02576dbaf194433005e154d3a6f48b39a3d571a8291be2bb5b3aaec2ec5b2b700cdd38fa1f29bad537037a055c899dca3963fd43a5cfac9fb60cc8f707c8b6b1392b96867bee317984fec29a374977a6770e760de22ac49fb5d6ee2042818129995eca01dd27d96cad32d045f0a73bd43541c9580c38566a11e16d9bd890d18cf85ac146066626e07aaedd0d000000000000000000000000000000000000000000000000000000000000000001478f34915199396487c16eb0d27468b3d15c0f818d85f8fe132e42d79e350b521718e5dac77ece73f6d67a786427f0db835faf42af133760ac660761d0fd86009e81af0ba8e79de3c259cf4e67a870561016500c4f5005c196fa492b767fe58f2 2 | -------------------------------------------------------------------------------- /services/graphql/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graphql-service" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | byteorder = "1" 10 | hex = "0.4" 11 | chrono = "0.4" 12 | prost = "0.8" 13 | serde_json = "1.0" 14 | tokio = { version = "1", default-features = false } 15 | async-graphql = { version = "2.10.1", default-features = false, features = [ 16 | "chrono", 17 | "chrono-tz", 18 | "string_number", 19 | ] } 20 | async-graphql-warp = "2.10.1" 21 | # dataloader = "0.14" 22 | # async-trait = "0.1" 23 | warp = { version = "0.3", default-features = false } 24 | http = "0.2" 25 | sysinfo = "0.20" 26 | # workspace 27 | types = { path = "../../types" } 28 | keys = { path = "../../keys" } 29 | proto = { path = "../../proto" } 30 | state = { path = "../../state" } 31 | chain = { path = "../../chain" } 32 | chain-db = { path = "../../chain-db" } 33 | context = { path = "../../context" } 34 | manager = { path = "../../manager" } 35 | -------------------------------------------------------------------------------- /services/graphql/src/model.rs: -------------------------------------------------------------------------------- 1 | use async_graphql::SimpleObject; 2 | 3 | /// Running node info. 4 | #[derive(SimpleObject)] 5 | pub struct NodeInfo { 6 | /// Node name, generated by system info. 7 | pub name: String, 8 | /// Running code version. 9 | pub code_version: &'static str, 10 | /// Is node syncing. 11 | pub syncing: bool, 12 | /// Number of active(outgoing) connections. 13 | pub num_active_connections: u32, 14 | /// Number of passive(incoming) connections. 15 | pub num_passive_connections: u32, 16 | /// Number of currently running compactions. 17 | pub num_running_compactions: i32, 18 | /// Number of currently running flushes. 19 | pub num_running_flushes: i32, 20 | /// Number of immutable memtables that have not yet been flushed. 21 | pub num_immutable_mem_table: i32, 22 | /// If write has been stopped. 23 | pub is_write_stopped: bool, 24 | /// Total size (bytes) of all SST files belong to the latest LSM tree. 25 | pub total_size: i64, 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 The OpenTron Developers 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /docs/graphql.md: -------------------------------------------------------------------------------- 1 | # The GraphQL API 2 | 3 | OpenTron natively supports GraphQL, in [EIP-1767](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1767.md) style. 4 | 5 | Current GraphQL API of OpenTron is an experimental one, which means it might changes often. 6 | Feel free to make a feature request or bug request. 7 | 8 | ## Get started 9 | 10 | To enable GraphQL support, you need to check the following section in `etc/config.toml`: 11 | 12 | ```toml 13 | [graphql] 14 | enable = true 15 | endpoint = "0.0.0.0:3000" 16 | ``` 17 | 18 | Open your browser with , play with queries and mutations in GraphQL Playground. 19 | 20 | ## Queries 21 | 22 | ```text 23 | apiVersion 24 | nodeInfo: running state of OpenTron node 25 | syncing: syncing state of OpenTron node 26 | block: query block, almost the same API as EIP-1767 27 | blocks 28 | transaction 29 | logs: log entries filter style query 30 | account: account state query (state-db) 31 | call: dummy execute a transaction with current block state(like constant/view/pure call). 32 | estimateEnergy: estimate energy for a smart contract call 33 | asset: TRC10 query 34 | chain: chain parameter query(proposals) 35 | ``` 36 | 37 | ## Mutations 38 | 39 | ```text 40 | sendRawTransaction: TODO 41 | ``` 42 | -------------------------------------------------------------------------------- /proto/src/proto.discovery.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, PartialEq, ::prost::Message)] 2 | pub struct Ping { 3 | #[prost(message, optional, tag="1")] 4 | pub from: ::core::option::Option, 5 | #[prost(message, optional, tag="2")] 6 | pub to: ::core::option::Option, 7 | #[prost(int32, tag="3")] 8 | pub version: i32, 9 | #[prost(int64, tag="4")] 10 | pub timestamp: i64, 11 | } 12 | #[derive(Clone, PartialEq, ::prost::Message)] 13 | pub struct Pong { 14 | #[prost(message, optional, tag="1")] 15 | pub from: ::core::option::Option, 16 | #[prost(int32, tag="2")] 17 | pub echo_version: i32, 18 | #[prost(int64, tag="3")] 19 | pub timestamp: i64, 20 | } 21 | /// renamed: FindNeighbours 22 | #[derive(Clone, PartialEq, ::prost::Message)] 23 | pub struct FindPeers { 24 | #[prost(message, optional, tag="1")] 25 | pub from: ::core::option::Option, 26 | #[prost(bytes="vec", tag="2")] 27 | pub target_id: ::prost::alloc::vec::Vec, 28 | #[prost(int64, tag="3")] 29 | pub timestamp: i64, 30 | } 31 | /// renamed: Neighbours 32 | #[derive(Clone, PartialEq, ::prost::Message)] 33 | pub struct Peers { 34 | #[prost(message, optional, tag="1")] 35 | pub from: ::core::option::Option, 36 | #[prost(message, repeated, tag="2")] 37 | pub peers: ::prost::alloc::vec::Vec, 38 | #[prost(int64, tag="3")] 39 | pub timestamp: i64, 40 | } 41 | -------------------------------------------------------------------------------- /keys/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Key Errors. 2 | use std::fmt; 3 | 4 | use libsecp256k1::Error as Secp256k1Error; 5 | 6 | /// Key Errors. 7 | #[derive(Debug, PartialEq)] 8 | pub enum Error { 9 | /// Public key format error. 10 | InvalidPublic, 11 | /// Digest data format error. 12 | InvalidMessage, 13 | /// Signature data format error. 14 | InvalidSignature, 15 | /// Invalid checksum of base58check. 16 | InvalidChecksum, 17 | /// Private key format error. 18 | InvalidPrivate, 19 | /// Invalid address format. 20 | InvalidAddress, 21 | /// Unable to generate a key pair. 22 | FailedKeyGeneration, 23 | } 24 | 25 | impl fmt::Display for Error { 26 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 27 | let msg = match *self { 28 | Error::InvalidPublic => "Invalid Public", 29 | Error::InvalidMessage => "Invalid Message", 30 | Error::InvalidSignature => "Invalid Signature", 31 | Error::InvalidChecksum => "Invalid Checksum", 32 | Error::InvalidPrivate => "Invalid Private", 33 | Error::InvalidAddress => "Invalid Address", 34 | Error::FailedKeyGeneration => "Key generation failed", 35 | }; 36 | 37 | msg.fmt(f) 38 | } 39 | } 40 | 41 | impl std::error::Error for Error {} 42 | 43 | impl From for Error { 44 | fn from(e: Secp256k1Error) -> Self { 45 | match e { 46 | Secp256k1Error::InvalidPublicKey => Error::InvalidPublic, 47 | Secp256k1Error::InvalidSecretKey => Error::InvalidPrivate, 48 | Secp256k1Error::InvalidMessage => Error::InvalidMessage, 49 | _ => Error::InvalidSignature, 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /opentron/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "opentron" 3 | version = "0.1.0" 4 | authors = ["OpenTron Developers "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | 8 | [lib] 9 | name = "opentron" 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "opentron" 14 | path = "src/main.rs" 15 | 16 | [features] 17 | default = [] 18 | nile = ["javatron"] 19 | 20 | # the default behaviour 21 | opentron = ["context/default"] 22 | 23 | # javatron compatible 24 | javatron = ["context/javatron"] 25 | 26 | # link against builtin static rocksdb 27 | static-rocksdb = ["context/static-rocksdb"] 28 | 29 | [dependencies] 30 | # app 31 | clap = { version = "2", features = ["yaml"] } 32 | ctrlc = { version = "3", features = ["termination"] } 33 | num_cpus = "1.13.0" 34 | # logger 35 | log = "0.4" 36 | slog = "2.7" 37 | slog-term = "2.6" 38 | slog-async = "2.6" 39 | slog-stdlog = "4.1" 40 | slog-scope = "4.4" 41 | slog-scope-futures = "0.1" 42 | # runner 43 | futures = "0.3" 44 | tokio = { version = "1", default-features = false, features = [ 45 | "rt", 46 | "rt-multi-thread", 47 | "macros", 48 | "net", 49 | "time", 50 | ] } 51 | # misc 52 | serde = { version = "1.0", features = ["derive"] } 53 | chrono = "0.4" 54 | byteorder = "1" 55 | reqwest = { version = "0.11", default-features = false, features = ["blocking", "json"] } 56 | # workspace 57 | keys = { path = "../keys" } 58 | chain-db = { path = "../chain-db" } 59 | config = { path = "../config" } 60 | context = { path = "../context" } 61 | discovery-service = { path = "../services/discovery" } 62 | channel-service = { path = "../services/channel" } 63 | graphql-service = { path = "../services/graphql" } 64 | producer-service = { path = "../services/producer" } 65 | -------------------------------------------------------------------------------- /ztron/tests/precompiles.rs: -------------------------------------------------------------------------------- 1 | extern crate ztron; 2 | 3 | use ztron::precompiles::*; 4 | 5 | #[test] 6 | fn test_verify_mint_proof() { 7 | let raw = include_str!("./mint.hex").trim(); 8 | let input = hex::decode(raw).unwrap(); 9 | 10 | println!("len={} words={}", input.len(), input.len() as f64 / 32.0); 11 | 12 | let ret = verify_mint_proof(&input); 13 | assert!(ret.is_ok()); 14 | for word in ret.unwrap().chunks(32) { 15 | println!("=> {}", hex::encode(word)); 16 | } 17 | } 18 | 19 | #[test] 20 | fn test_verify_transfer_proof() { 21 | let raw = include_str!("./transfer.hex").trim(); 22 | let input = hex::decode(raw).unwrap(); 23 | 24 | println!("len={} words={}", input.len(), input.len() as f64 / 32.0); 25 | 26 | let ret = verify_transfer_proof(&input); 27 | assert!(ret.is_ok()); 28 | for word in ret.unwrap().chunks(32) { 29 | println!("=> {}", hex::encode(word)); 30 | } 31 | } 32 | 33 | #[test] 34 | fn test_verify_transfer_proof_1_to_2() { 35 | let raw = include_str!("./transfer.to2.hex").trim(); 36 | let input = hex::decode(raw).unwrap(); 37 | 38 | println!("len={} words={}", input.len(), input.len() as f64 / 32.0); 39 | 40 | let ret = verify_transfer_proof(&input); 41 | assert!(ret.is_ok()); 42 | for word in ret.unwrap().chunks(32) { 43 | println!("=> {}", hex::encode(word)); 44 | } 45 | } 46 | 47 | #[test] 48 | fn test_verify_burn_proof() { 49 | let raw = include_str!("./burn.hex").trim(); 50 | let input = hex::decode(raw).unwrap(); 51 | 52 | println!("len={} words={}", input.len(), input.len() as f64 / 32.0); 53 | 54 | let ret = verify_burn_proof(&input); 55 | println!("ret => {:?}", ret); 56 | assert!(ret.is_ok()); 57 | } 58 | -------------------------------------------------------------------------------- /cli/src/witness.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use keys::Address; 3 | use proto::chain::transaction::Contract; 4 | use proto::contract as contract_pb; 5 | 6 | pub fn main(matches: &ArgMatches) -> Option { 7 | match matches.subcommand() { 8 | ("create", Some(arg_matches)) => create(arg_matches), 9 | ("update_brokerage", Some(arg_matches)) => update_brokerage(arg_matches), 10 | ("update_url", Some(arg_matches)) => update_url(arg_matches), 11 | _ => unimplemented!(), 12 | } 13 | } 14 | 15 | fn create(matches: &ArgMatches) -> Option { 16 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 17 | let url = matches.value_of("URL").expect("required; qed"); 18 | 19 | let inner = contract_pb::WitnessCreateContract { 20 | owner_address: from.as_bytes().into(), 21 | url: url.as_bytes().into(), 22 | }; 23 | 24 | Some(inner.into()) 25 | } 26 | 27 | fn update_brokerage(matches: &ArgMatches) -> Option { 28 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 29 | let percent = matches.value_of("PERCENT").expect("required; qed"); 30 | 31 | let inner = contract_pb::UpdateBrokerageContract { 32 | owner_address: from.as_bytes().into(), 33 | brokerage: percent.parse().ok()?, 34 | }; 35 | 36 | Some(inner.into()) 37 | } 38 | 39 | fn update_url(matches: &ArgMatches) -> Option { 40 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 41 | let url = matches.value_of("URL").expect("required; qed"); 42 | 43 | let inner = contract_pb::WitnessUpdateContract { 44 | owner_address: from.as_bytes().into(), 45 | new_url: url.as_bytes().into(), 46 | }; 47 | 48 | Some(inner.into()) 49 | } 50 | -------------------------------------------------------------------------------- /opentron/src/commands/key.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use keys::{Address, KeyPair}; 3 | 4 | type Error = Box; 5 | 6 | pub fn main(matches: &ArgMatches<'_>) -> Result<(), Error> { 7 | match matches.subcommand() { 8 | ("generate", _) => generate_key(), 9 | ("inspect", Some(arg_matches)) => inspect_key(arg_matches), 10 | // ("generate-genesis-key", _) => unimplemented!(), 11 | _ => { 12 | eprintln!("{}", matches.usage()); 13 | Ok(()) 14 | } 15 | } 16 | } 17 | 18 | fn generate_key() -> Result<(), Error> { 19 | let kp = KeyPair::generate(); 20 | let address = kp.address(); 21 | 22 | println!("Public: {:}", kp.public()); 23 | println!("Private: {:}", kp.private()); 24 | pprint_address(&address); 25 | Ok(()) 26 | } 27 | 28 | fn inspect_key(matches: &ArgMatches<'_>) -> Result<(), Error> { 29 | let address = match matches.value_of("ADDRESS") { 30 | Some(raw_addr) => raw_addr.parse()?, 31 | _ if matches.is_present("private") => { 32 | let priv_key: keys::Private = matches.value_of("private").unwrap().parse()?; 33 | let kp = KeyPair::from_private(priv_key)?; 34 | println!("Public: {:}", kp.public()); 35 | println!("Private: {:}", kp.private()); 36 | kp.address() 37 | } 38 | _ if matches.is_present("public") => { 39 | let pub_key: keys::Public = matches.value_of("public").unwrap().parse()?; 40 | println!("Public: {:}", pub_key); 41 | Address::from_public(&pub_key) 42 | } 43 | _ => { 44 | eprintln!("{}", matches.usage()); 45 | return Ok(()); 46 | } 47 | }; 48 | 49 | pprint_address(&address); 50 | Ok(()) 51 | } 52 | 53 | fn pprint_address(address: &Address) { 54 | println!("Address:"); 55 | println!(" - Base58: {:}", address); 56 | println!(" - HEX: {:}", address.to_hex_address()); 57 | println!(" - ETH: {:}", address.to_eth_address()); 58 | } 59 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | submodules: true 13 | 14 | - name: Install nightly toolchain with clippy available 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: nightly 19 | override: true 20 | components: rustfmt, clippy 21 | 22 | - name: Install dependencies 23 | run: sudo apt-get install protobuf-compiler libprotobuf-dev libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev libzstd-dev 24 | 25 | - name: Cache Rust build 26 | uses: actions/cache@v2 27 | with: 28 | path: | 29 | ~/.cargo/registry 30 | ~/.cargo/git 31 | target 32 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 33 | 34 | - name: Cache ztron-params 35 | id: cache-ztron-params 36 | uses: actions/cache@v2 37 | with: 38 | path: ./ztron-params 39 | key: ztron-params 40 | 41 | - name: Download ztron-params 42 | if: steps.cache-ztron-params.outputs.cache-hit != 'true' 43 | run: | 44 | ./scripts/download-ztron-params.sh 45 | 46 | - name: Prepare ztron-params for tests 47 | run: | 48 | cp -r ./ztron-params ./ztron/ 49 | 50 | # ldd fix: https://users.rust-lang.org/t/cannot-find-ld-when-using-lld/47420 51 | - name: Run tests 52 | run: | 53 | sudo ln -sf /usr/bin/ld.lld-9 /usr/bin/ld.lld 54 | cargo test -p opentron --features static-rocksdb 55 | env: 56 | LD_LIBRARY_PATH: /usr/local/lib 57 | -------------------------------------------------------------------------------- /tvm/src/lib.rs: -------------------------------------------------------------------------------- 1 | use types::H160; 2 | 3 | pub use evm::executor::StackExecutor; 4 | pub use evm::{Config, Context, ExitError, ExitFatal, ExitReason, ExitSucceed, Runtime}; 5 | 6 | use self::backend::Backend; 7 | 8 | pub mod backend; 9 | pub mod precompile; 10 | 11 | /// Handle TVM upgrades. 12 | #[derive(Debug, Clone, Default)] 13 | pub struct TvmUpgrade { 14 | /// AllowTvmTransferTrc10Upgrade 15 | pub asset_transfer: bool, 16 | /// AllowTvmConstantinopleUpgrade 17 | pub constantinople: bool, 18 | /// AllowTvmSolidity059Upgrade, has batchvalidatesign, validatemultisign precompile. 19 | pub solidity059: bool, 20 | /// AllowTvmShieldedUpgrade, a precompile only upgrade. 21 | pub shielded: bool, 22 | /// AllowTvmStakeUpgrade 23 | pub stake: bool, 24 | /// AllowTvmIstanbulUpgrade 25 | pub istanbul: bool, 26 | /// AllowTvmAssetIssueUpgrade 27 | pub asset_issue: bool, 28 | /// AllowMultisig 29 | pub multisig: bool, 30 | } 31 | 32 | impl TvmUpgrade { 33 | fn validate(&self) -> bool { 34 | if self.constantinople && !self.asset_transfer { 35 | return false; 36 | } 37 | true 38 | } 39 | 40 | pub fn precompile( 41 | &self, 42 | ) -> fn(H160, &[u8], Option, &dyn Backend) -> Option, usize), ExitError>> { 43 | return self::precompile::tron_precompile; 44 | } 45 | 46 | pub fn to_tvm_config(&self) -> Config { 47 | if !self.validate() { 48 | panic!("inconsistent TVM state"); 49 | } 50 | let mut config = Config::tvm(); 51 | if self.multisig { 52 | config.has_buggy_origin = false; 53 | } 54 | if self.asset_transfer { 55 | config.allow_tvm_asset_transfer(); 56 | } 57 | if self.constantinople { 58 | config.allow_tvm_constantinople(); 59 | } 60 | if self.solidity059 { 61 | config.allow_tvm_solidity059(); 62 | } 63 | // TODO: handle 4.1 update. 64 | config 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cli/src/account.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use keys::Address; 3 | use proto::chain::transaction::Contract; 4 | use proto::contract as contract_pb; 5 | 6 | pub fn main(matches: &ArgMatches) -> Option { 7 | match matches.subcommand() { 8 | ("create", Some(arg_matches)) => create(arg_matches), 9 | ("set_name", Some(arg_matches)) => set_name(arg_matches), 10 | ("set_id", Some(arg_matches)) => set_id(arg_matches), 11 | _ => unimplemented!(), 12 | } 13 | } 14 | 15 | fn create(matches: &ArgMatches) -> Option { 16 | use proto::common::AccountType; 17 | 18 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 19 | let to: Address = matches.value_of("RECIPIENT")?.parse().ok()?; 20 | 21 | let account_type = match matches.value_of("type") { 22 | Some("Normal") => AccountType::Normal, 23 | Some("AssetIssue") => AccountType::AssetIssue, 24 | Some("Contract") => AccountType::Contract, 25 | _ => unreachable!("values restricted; qed"), 26 | }; 27 | 28 | let inner = contract_pb::AccountCreateContract { 29 | owner_address: from.as_bytes().into(), 30 | account_address: to.as_bytes().into(), 31 | r#type: account_type as i32, 32 | }; 33 | Some(inner.into()) 34 | } 35 | 36 | fn set_name(matches: &ArgMatches) -> Option { 37 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 38 | let name = matches.value_of("NAME").expect("required; qed"); 39 | 40 | let inner = contract_pb::AccountUpdateContract { 41 | owner_address: from.as_bytes().into(), 42 | account_name: name.into(), 43 | }; 44 | Some(inner.into()) 45 | } 46 | 47 | fn set_id(matches: &ArgMatches) -> Option { 48 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 49 | let id = matches.value_of("ID").expect("required; qed"); 50 | 51 | let inner = contract_pb::SetAccountIdContract { 52 | owner_address: from.as_bytes().into(), 53 | account_id: id.into(), 54 | }; 55 | Some(inner.into()) 56 | } 57 | -------------------------------------------------------------------------------- /docs/txpool.md: -------------------------------------------------------------------------------- 1 | # Txpool - How transaction is handled 2 | 3 | ## FullNode.java 4 | 5 | Application 6 | 7 | ``` 8 | tronNetService.start(); 9 | consensusService.start(); 10 | MetricsUtil.init(); 11 | appT.addService(rpcApiService); 12 | appT.addService(httpApiService); 13 | appT.addService(rpcApiServiceOnSolidity); 14 | appT.addService(httpApiOnSolidityService); 15 | appT.addService(rpcApiServiceOnPBFT); 16 | appT.addService(httpApiOnPBFTService); 17 | ``` 18 | 19 | ### tronNetService 20 | 21 | ``` 22 | channelManager 23 | advService 24 | syncService 25 | peerStatusCheck 26 | 27 | message handlers(channel message): 28 | SYNC_BLOCK_CHAIN 29 | BLOCK_CHAIN_INVENTORY 30 | INVENTORY => Adv(hashes) 31 | - Transaction 32 | - Block 33 | FETCH_INV_DATA 34 | - Transaction 35 | - Block 36 | BLOCK 37 | TRXS 38 | PBFT_COMMIT_MSG 39 | ``` 40 | 41 | ### rpcApiService(broadcastTransaction) 42 | 43 | ``` 44 | wallet.broadcastTransaction(req) 45 | Wallet(broadcastTransaction) 46 | 47 | steps: 48 | 49 | - check minEffectiveConnection 50 | - check tooManyPending (maxTransactionPendingSize = 2000) 51 | - check already exists (in ids cache) 52 | - dbManager.pushTransaction(trx) 53 | - processTransaction 54 | - ? push and throws many types of errors 55 | - signature validation 56 | - execute error 57 | - resouce check 58 | - dup transaction 59 | - tapos check 60 | - expiration check 61 | - ... 62 | - tronNetService.broadcast(message) 63 | - advService.broadcast 64 | ``` 65 | 66 | ### consensusService 67 | 68 | The miners. 69 | 70 | ``` 71 | getBlockProducedTimeOut = 50%. 72 | 73 | BlockHandle.produce(Miner miner, long blockTime, long timeout) 74 | manager.generateBlock(miner, blockTime, timeout) 75 | 76 | Consensus.start() 77 | - DposService.start() 78 | - dposTask.init() 79 | - calling produceBlock 80 | - manager.generateBlock 81 | ``` 82 | 83 | ## Block Produce 84 | 85 | ``Manager.generateBlock(Miner miner, long blockTime, long timeout)`` 86 | 87 | - Generate block header 88 | - iterater over pendingTransactions and rePushTransactions 89 | - processTransaction -------------------------------------------------------------------------------- /proto/proto/channel.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package proto.channel; 4 | 5 | import "common.proto"; 6 | import "chain.proto"; 7 | 8 | message HandshakeHello { 9 | proto.common.Endpoint from = 1; 10 | int32 version = 2; 11 | int64 timestamp = 3; 12 | proto.common.BlockId genesis_block_id = 4; // number=0 13 | proto.common.BlockId solid_block_id = 5; 14 | proto.common.BlockId head_block_id = 6; 15 | bytes address = 7; 16 | bytes signature = 8; 17 | } 18 | 19 | enum ReasonCode { 20 | REQUESTED = 0x00; 21 | BAD_PROTOCOL = 0x02; 22 | TOO_MANY_PEERS = 0x04; 23 | DUPLICATE_PEER = 0x05; 24 | INCOMPATIBLE_PROTOCOL = 0x06; 25 | NULL_IDENTITY = 0x07; 26 | PEER_QUITING = 0x08; 27 | UNEXPECTED_IDENTITY = 0x09; 28 | LOCAL_IDENTITY = 0x0A; 29 | PING_TIMEOUT = 0x0B; 30 | USER_REASON = 0x10; 31 | RESET = 0x11; 32 | SYNC_FAIL = 0x12; 33 | FETCH_FAIL = 0x13; 34 | BAD_TX = 0x14; 35 | BAD_BLOCK = 0x15; 36 | FORKED = 0x16; 37 | UNLINKABLE = 0x17; 38 | INCOMPATIBLE_VERSION = 0x18; 39 | INCOMPATIBLE_CHAIN = 0x19; 40 | TIME_OUT = 0x20; 41 | CONNECT_FAIL = 0x21; 42 | TOO_MANY_PEERS_WITH_SAME_IP = 0x22; 43 | UNKNOWN = 0xFF; 44 | } 45 | 46 | message HandshakeDisconnect { 47 | ReasonCode reason = 1; 48 | } 49 | 50 | message ChainInventory { 51 | repeated proto.common.BlockId ids = 1; 52 | int64 remain_num = 2; 53 | } 54 | 55 | message BlockInventory { 56 | enum Type { 57 | SYNC = 0; 58 | ADVTISE = 1; // unused 59 | FETCH = 2; // unused 60 | } 61 | repeated proto.common.BlockId ids = 1; 62 | Type type = 2; 63 | } 64 | 65 | message Inventory { 66 | enum Type { 67 | TRX = 0; 68 | BLOCK = 1; 69 | } 70 | Type type = 1; 71 | repeated bytes ids = 2; 72 | } 73 | 74 | message Transactions { 75 | repeated proto.chain.Transaction transactions = 1; 76 | } 77 | 78 | /* 79 | message Items { 80 | enum ItemType { 81 | ERR = 0; 82 | TRX = 1; 83 | BLOCK = 2; 84 | BLOCKHEADER = 3; 85 | } 86 | 87 | ItemType type = 1; 88 | repeated Block blocks = 2; 89 | repeated BlockHeader block_headers = 3; 90 | repeated Transaction transactions = 4; 91 | } 92 | */ 93 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Install 2 | 3 | 4 | 5 | 6 | - [MacOS](#macos) 7 | - [CentOS 7](#centos-7) 8 | - [Windows](#windows) 9 | - [Other Platforms](#other-platforms) 10 | 11 | 12 | 13 | ## MacOS 14 | 15 | ```bash 16 | # Install RocksDB (https://github.com/bh1xuw/rust-rocks#how-to-compile) 17 | brew install rocksdb 18 | 19 | # Install Protobuf 20 | brew install protobuf cmake wget 21 | 22 | # Clone opentron 23 | git clone https://github.com/opentron/opentron.git 24 | cd opentron 25 | 26 | # Download ztron params 27 | ./scripts/download-ztron-params.sh 28 | 29 | # build all 30 | cargo build 31 | # run tests 32 | cargo test 33 | ``` 34 | 35 | ## CentOS 7 36 | 37 | ```bash 38 | # (This official repo's protobuf-compiler is out-dated.) 39 | # (Unrecognized syntax identifier "proto3". This parser only recognizes "proto".) 40 | 41 | wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip 42 | unzip protoc-3.11.4-linux-x86_64.zip 43 | sudo cp -rv bin include /usr/local 44 | 45 | git clone --recurse-submodules https://github.com/opentron/opentron.git 46 | cd opentron 47 | 48 | # Download ztron params 49 | ./scripts/download-ztron-params.sh 50 | 51 | cargo build -p opentron --features static-rocksdb 52 | ``` 53 | 54 | ## Windows 55 | 56 | You need to have VS 2019 Developer Tools, MSYS2 and vcpkg installed. 57 | 58 | ```bash 59 | vcpkg install rocksdb[snappy]:x64-windows-static-md 60 | 61 | ./scripts/download-ztron-params.sh 62 | 63 | cargo build 64 | ``` 65 | 66 | ## Other Platforms 67 | 68 | Java-tron requires `x64(x86_64)` architecture. It is because it uses `java.math` wrongly 69 | and relies on `8087` extended precision float point arithmetic. 70 | 71 | For non-x64 architectures, you can still build and run OpenTron, but it won't be compatible with 72 | original java-tron. 73 | 74 | This project can be run on following platforms: 75 | 76 | - Apple Silicon 77 | - Raspberry Pi 4(or 3+) 78 | -------------------------------------------------------------------------------- /docs/tvm.md: -------------------------------------------------------------------------------- 1 | # TVM 2 | 3 | ## Diffs vs EVM 4 | 5 | - rename gas to energy 6 | - yes, rename 7 | - some opcode consumes lower energy point 8 | - `gasprice` = 0 9 | - `block.gaslimit` = 0 10 | - `block.difficulty` = 0 11 | - buggy `COINBASE` opcode which returns 21 bytes 12 | - no energy refund 13 | - there're variables tracking refunds, but not used in the final calculation 14 | - storage set/reset energy is buggy 15 | - a hidden bug caused by comparing variable to null 16 | - java is not null-safe 17 | - buggy exception handling with `TransactionException` 18 | - different constract address calculation from `CREATE2`, `CREATE` 19 | 20 | ## Stages 21 | 22 | ### AllowTvm = 9 23 | 24 | Version: 2.1 25 | 26 | ### AllowTvmTransferTrc10Upgrade = 18 27 | 28 | Version: 3.2 29 | 30 | CALLTOKEN, TOKENBALANCE, CALLTOKENVALUE, CALLTOKENID 31 | 32 | ### AllowMultisig = 20 33 | 34 | Version: 3.5 35 | 36 | - Add `isTokenTransferMsg = true` property to token call. Check token id 37 | - Fix `ORIGIN` opcode, 21-bytes to 20-byte 38 | 39 | NOTE: This TVM change is under multisig scope. Might be useless. 40 | 41 | ### AllowTvmConstantinopleUpgrade = 26 42 | 43 | Version: 3.6.0 44 | 45 | - ClearABI builtin contract 46 | - reject delegate resource to contract address 47 | - Save runtime code from execution result of deploy code 48 | - OpCode: SHL, SHR, SAR, EXTCODEHASH, fake and buggy CREATE2 49 | - Introduce TransferException 50 | 51 | ### AllowTvmSolidity059Upgrade = 32 52 | 53 | Version: 3.6.5 54 | 55 | - create account while transfer TRX/TRC10 56 | - Precompile: batchvalidatesign, validatemultisign 57 | - OpCode: ISCONTRACT 58 | 59 | ### AllowTvmShieldedUpgrade = 39 60 | 61 | Version: 4.0.0 / 4.0.1 62 | 63 | - Precompile: verifyMintProof, verifyTransferProof, verifyBurnProof, pedersenHash 64 | 65 | NOTE: `pedersenHash` is called `merkleTree` in java-tron, which is inconsistent. 66 | 67 | ### AllowTvmIstanbulUpgrade 68 | 69 | Version: 4.1.0 70 | 71 | - Impl EVM OpCode: CHAINID, SELFBALANCE 72 | - OpCode Change: 73 | - CREATE2 impl 74 | - Precompile Change: 75 | - bn128add: energy change from 500 to 150 76 | - bn128mul: energy change from 40000 to 6000 77 | - bn128pairing: energy change 78 | -------------------------------------------------------------------------------- /chain/src/block_builder.rs: -------------------------------------------------------------------------------- 1 | use crate::{BlockHeader, IndexedBlock, IndexedBlockHeader, Transaction}; 2 | use keys::{Address, KeyPair}; 3 | use prost::Message; 4 | use types::H256; 5 | 6 | pub struct BlockBuilder { 7 | header: BlockHeader, 8 | txns: Vec, 9 | } 10 | 11 | impl BlockBuilder { 12 | pub fn new(number: i64) -> Self { 13 | let mut header = BlockHeader::default(); 14 | header.raw_data = Some(Default::default()); 15 | header.raw_data.as_mut().map(|h| { 16 | h.number = number; 17 | }); 18 | BlockBuilder { header, txns: vec![] } 19 | } 20 | 21 | pub fn timestamp(mut self, timestamp: i64) -> Self { 22 | self.header.raw_data.as_mut().map(|h| h.timestamp = timestamp); 23 | self 24 | } 25 | 26 | pub fn version(mut self, version: i32) -> Self { 27 | self.header.raw_data.as_mut().map(|h| h.version = version); 28 | self 29 | } 30 | 31 | pub fn parent_hash(mut self, hash: &H256) -> Self { 32 | self.header 33 | .raw_data 34 | .as_mut() 35 | .map(|h| h.parent_hash = hash.as_bytes().into()); 36 | self 37 | } 38 | 39 | pub fn witness(mut self, witness: &Address) -> Self { 40 | self.header 41 | .raw_data 42 | .as_mut() 43 | .map(|h| h.witness_address = witness.as_bytes().into()); 44 | self 45 | } 46 | 47 | pub fn push_transaction(&mut self, txn: Transaction) { 48 | self.txns.push(txn); 49 | } 50 | 51 | pub fn to_unsigned_block_header(&self) -> IndexedBlockHeader { 52 | IndexedBlockHeader::from_raw(self.header.clone()).unwrap() 53 | } 54 | 55 | pub fn build(self, keypair: &KeyPair) -> Option { 56 | let block = IndexedBlock::from_raw_header_and_txns(self.header, self.txns); 57 | 58 | block.and_then(|mut b| { 59 | let mut buf = Vec::with_capacity(255); 60 | b.header.raw.raw_data.as_ref().unwrap().encode(&mut buf).unwrap(); 61 | let signature = keypair.private().sign(&buf).ok()?; 62 | b.header.raw.witness_signature = signature.as_bytes().into(); 63 | Some(b) 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /opentron/src/cli.yml: -------------------------------------------------------------------------------- 1 | name: opentron 2 | version: "0.1.0" 3 | author: OpenTron Developers 4 | about: Tron Protocol Full Node Implementation. 5 | settings: &default_settings 6 | - DisableHelpSubcommand 7 | - VersionlessSubcommands 8 | 9 | args: 10 | - config: 11 | help: Path to config file 12 | short: c 13 | long: config 14 | default_value: "./etc/conf.toml" 15 | 16 | - debug: 17 | help: Enable debug logs (dev mode) 18 | long: debug 19 | 20 | subcommands: 21 | - run: 22 | about: Run the node 23 | settings: *default_settings 24 | 25 | - check: 26 | about: Check db consistency 27 | args: 28 | - WHAT: 29 | help: Check item 30 | # possible_values: ["compact", "merkle_tree", "parent_hash"] 31 | 32 | - fix: 33 | about: Misc fix command 34 | args: 35 | - height: 36 | help: Force update block height 37 | takes_value: true 38 | long: height 39 | value_name: NUM 40 | - fork: 41 | help: Fix chain fork at position 42 | takes_value: true 43 | long: fork 44 | value_name: NUM 45 | - dev: 46 | about: Dev command 47 | - key: 48 | about: Key tools 49 | settings: *default_settings 50 | subcommands: 51 | - generate: 52 | about: Generate key pair 53 | - inspect: 54 | about: Inspect a key 55 | args: 56 | - ADDRESS: 57 | help: Address in any format 58 | - public: 59 | help: Public key in hex 60 | takes_value: true 61 | long: public 62 | value_name: PUBLIC_KEY 63 | - private: 64 | help: Private key in hex 65 | takes_value: true 66 | long: private 67 | value_name: PRIVATE_KEY 68 | -------------------------------------------------------------------------------- /cli/src/proposal.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use keys::Address; 3 | use proto::chain::transaction::Contract; 4 | use proto::contract as contract_pb; 5 | use std::collections::HashMap; 6 | 7 | use crate::{custom_error, Result}; 8 | 9 | pub fn main(matches: &ArgMatches) -> Result { 10 | match matches.subcommand() { 11 | ("create", Some(arg_matches)) => create(arg_matches), 12 | ("approve", Some(arg_matches)) => approve(arg_matches), 13 | ("delete", Some(arg_matches)) => delete(arg_matches), 14 | _ => unreachable!("checked; qed"), 15 | } 16 | } 17 | 18 | fn create(matches: &ArgMatches) -> Result { 19 | let from: Address = matches.value_of("SENDER").expect("required; qed").parse()?; 20 | let params = matches 21 | .values_of("PARAMS") 22 | .expect("required in cli.yml; qed") 23 | .map(|pair| { 24 | if let [key, val] = &pair.split('=').collect::>()[..] { 25 | Ok((key.parse::()?, val.parse::()?)) 26 | } else { 27 | Err(custom_error("malformed key=value PARAMS")) 28 | } 29 | }); 30 | 31 | let inner = contract_pb::ProposalCreateContract { 32 | owner_address: from.as_bytes().into(), 33 | parameters: params.collect::>>()?, 34 | }; 35 | 36 | Ok(inner.into()) 37 | } 38 | 39 | fn approve(matches: &ArgMatches) -> Result { 40 | let from: Address = matches.value_of("SENDER").expect("required; qed").parse()?; 41 | let id = matches.value_of("ID").expect("required; qed"); 42 | 43 | let is_approval = matches.value_of("approve").expect("required; qed") == "yes"; 44 | 45 | let inner = contract_pb::ProposalApproveContract { 46 | owner_address: from.as_bytes().into(), 47 | proposal_id: id.parse()?, 48 | is_approval, 49 | }; 50 | 51 | Ok(inner.into()) 52 | } 53 | 54 | fn delete(matches: &ArgMatches) -> Result { 55 | let from: Address = matches.value_of("SENDER").expect("required; qed").parse()?; 56 | let id = matches.value_of("ID").expect("required; qed"); 57 | 58 | let inner = contract_pb::ProposalDeleteContract { 59 | owner_address: from.as_bytes().into(), 60 | proposal_id: id.parse()?, 61 | }; 62 | 63 | Ok(inner.into()) 64 | } 65 | -------------------------------------------------------------------------------- /docs/proposal.md: -------------------------------------------------------------------------------- 1 | # Proposal 2 | 3 | ## Network Parameters 4 | 5 | 6 | 7 | ## Id of Proposal 8 | 9 | ref: `ProposalUtil.java` 10 | 11 | ```java 12 | MAINTENANCE_TIME_INTERVAL(0), //ms ,0 13 | ACCOUNT_UPGRADE_COST(1), //drop ,1 14 | CREATE_ACCOUNT_FEE(2), //drop ,2 15 | TRANSACTION_FEE(3), //drop ,3 16 | ASSET_ISSUE_FEE(4), //drop ,4 17 | WITNESS_PAY_PER_BLOCK(5), //drop ,5 18 | WITNESS_STANDBY_ALLOWANCE(6), //drop ,6 19 | CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT(7), //drop ,7 20 | CREATE_NEW_ACCOUNT_BANDWIDTH_RATE(8), // 1 ~ ,8 21 | ALLOW_CREATION_OF_CONTRACTS(9), // 0 / >0 ,9 22 | REMOVE_THE_POWER_OF_THE_GR(10), // 1 ,10 23 | ENERGY_FEE(11), // drop, 11 24 | EXCHANGE_CREATE_FEE(12), // drop, 12 25 | MAX_CPU_TIME_OF_ONE_TX(13), // ms, 13 26 | ALLOW_UPDATE_ACCOUNT_NAME(14), // 1, 14 27 | ALLOW_SAME_TOKEN_NAME(15), // 1, 15 28 | ALLOW_DELEGATE_RESOURCE(16), // 0, 16 29 | TOTAL_ENERGY_LIMIT(17), // 50,000,000,000, 17 30 | ALLOW_TVM_TRANSFER_TRC10(18), // 1, 18 31 | TOTAL_CURRENT_ENERGY_LIMIT(19), // 50,000,000,000, 19 32 | ALLOW_MULTI_SIGN(20), // 1, 20 33 | ALLOW_ADAPTIVE_ENERGY(21), // 1, 21 34 | UPDATE_ACCOUNT_PERMISSION_FEE(22), // 100, 22 35 | MULTI_SIGN_FEE(23), // 1, 23 36 | ALLOW_PROTO_FILTER_NUM(24), // 1, 24 37 | ALLOW_ACCOUNT_STATE_ROOT(25), // 1, 25 38 | ALLOW_TVM_CONSTANTINOPLE(26), // 1, 26 39 | ALLOW_SHIELDED_TRANSACTION(27), // 27 40 | SHIELDED_TRANSACTION_FEE(28), // 28 41 | ADAPTIVE_RESOURCE_LIMIT_MULTIPLIER(29), // 1000, 29 42 | ALLOW_CHANGE_DELEGATION(30), //1, 30 43 | WITNESS_127_PAY_PER_BLOCK(31), //drop, 31 44 | ALLOW_TVM_SOLIDITY_059(32), // 1, 32 45 | ADAPTIVE_RESOURCE_LIMIT_TARGET_RATIO(33); // 10, 33 46 | FORBID_TRANSFER_TO_CONTRACT(35), // 1, {0, 1} 47 | ALLOW_SHIELDED_TRC20_TRANSACTION(39), // 1, 39 48 | ALLOW_PBFT(40),// 1,40 49 | ALLOW_TVM_ISTANBUL(41),//1, {0,1} 50 | ALLOW_MARKET_TRANSACTION(44), // {0, 1} 51 | MARKET_SELL_FEE(45), // 0 [0,10_000_000_000] 52 | MARKET_CANCEL_FEE(46), // 0 [0,10_000_000_000] 53 | MAX_FEE_LIMIT(47), // [0, 10_000_000_000] 54 | ALLOW_TRANSACTION_FEE_POOL(48), // 0, 1 55 | ALLOW_BLACKHOLE_OPTIMIZATION(49);// 0,1 56 | ALLOW_NEW_RESOURCE_MODEL(51),// 0,1 57 | ALLOW_TVM_FREEZE(52), // 0, 1 58 | ALLOW_ACCOUNT_ASSET_OPTIMIZATION(53), // 1 59 | ALLOW_TVM_VOTE(59), // 0, 1 60 | FREE_NET_LIMIT(61), // 5000, [0, 100_000] 61 | TOTAL_NET_LIMIT(62); // 43_200_000_000L, [0, 1000_000_000_000L] 62 | ``` 63 | -------------------------------------------------------------------------------- /services/graphql/src/server.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | use std::net::SocketAddr; 3 | use std::sync::Arc; 4 | 5 | use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; 6 | use async_graphql::{EmptySubscription, Schema}; 7 | use async_graphql_warp::BadRequest; 8 | use http::StatusCode; 9 | use log::{info, trace, warn}; 10 | use tokio::sync::broadcast; 11 | use warp::{Filter, Rejection}; 12 | 13 | use context::AppContext; 14 | 15 | use super::schema::{MutationRoot, QueryRoot}; 16 | 17 | pub async fn graphql_server(ctx: Arc, mut shutdown_signal: broadcast::Receiver<()>) { 18 | let config = &ctx.config.graphql; 19 | 20 | if !config.enable { 21 | warn!("graphql server disabled"); 22 | return; 23 | } 24 | 25 | let addr: SocketAddr = config 26 | .endpoint 27 | .parse() 28 | .expect("malformed endpoint address for graphql server"); 29 | 30 | let schema = Schema::build(QueryRoot, MutationRoot, EmptySubscription) 31 | .data(ctx) 32 | .finish(); 33 | 34 | let graphql_post = async_graphql_warp::graphql(schema).and_then( 35 | |(schema, request): (Schema<_, _, _>, async_graphql::Request)| async move { 36 | trace!("req: {:?}", request.query); 37 | Ok::<_, Infallible>(async_graphql_warp::Response::from(schema.execute(request).await)) 38 | }, 39 | ); 40 | let graphql_playground = warp::path::end().and(warp::get()).map(|| { 41 | warp::http::Response::builder() 42 | .header("content-type", "text/html") 43 | .body(playground_source(GraphQLPlaygroundConfig::new("/"))) 44 | }); 45 | 46 | let routes = graphql_playground 47 | .or(graphql_post) 48 | .recover(|err: Rejection| async move { 49 | if let Some(BadRequest(err)) = err.find() { 50 | return Ok::<_, Infallible>(warp::reply::with_status(err.to_string(), StatusCode::BAD_REQUEST)); 51 | } 52 | 53 | Ok(warp::reply::with_status( 54 | "INTERNAL_SERVER_ERROR".to_string(), 55 | StatusCode::INTERNAL_SERVER_ERROR, 56 | )) 57 | }); 58 | 59 | let (listening_addr, fut) = warp::serve(routes).bind_with_graceful_shutdown(addr, async move { 60 | shutdown_signal.recv().await.ok(); 61 | }); 62 | 63 | info!("listening on http://{}", listening_addr); 64 | 65 | fut.await; 66 | } 67 | -------------------------------------------------------------------------------- /chain/src/indexed_transaction.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | use std::convert::TryFrom; 3 | use std::hash::{Hash, Hasher}; 4 | 5 | use crypto::sha256; 6 | use keys::{Address, Public, Signature}; 7 | use prost::Message; 8 | use proto::chain::Transaction; 9 | use types::H256; 10 | 11 | #[derive(Default, Clone, Debug)] 12 | pub struct IndexedTransaction { 13 | pub hash: H256, 14 | pub raw: Transaction, 15 | } 16 | 17 | impl IndexedTransaction { 18 | pub fn new(hash: H256, transaction: Transaction) -> Self { 19 | IndexedTransaction { 20 | hash: hash, 21 | raw: transaction, 22 | } 23 | } 24 | 25 | /// Explicit conversion of the raw Transaction into IndexedTransaction. 26 | /// 27 | /// Hashes transaction contents. 28 | pub fn from_raw(transaction: T) -> Option 29 | where 30 | Transaction: From, 31 | { 32 | let transaction = Transaction::from(transaction); 33 | get_transaction_hash(&transaction).map(|hash| Self::new(hash, transaction)) 34 | } 35 | 36 | /// Recover owner address. 37 | pub fn recover_owner(&self) -> Result, keys::Error> { 38 | let mut buf = Vec::with_capacity(255); 39 | self.raw.raw_data.as_ref().unwrap().encode(&mut buf).unwrap(); 40 | 41 | self.raw 42 | .signatures 43 | .iter() 44 | .map(|raw_sig| { 45 | Signature::try_from(raw_sig) 46 | .and_then(|sig| Public::recover(&buf, &sig)) 47 | .map(|pk| Address::from_public(&pk)) 48 | }) 49 | .collect() 50 | } 51 | 52 | pub fn expiration(&self) -> i64 { 53 | self.raw.raw_data.as_ref().unwrap().expiration 54 | } 55 | 56 | pub fn verify(&self) -> bool { 57 | get_transaction_hash(&self.raw) 58 | .map(|hash| hash == self.hash) 59 | .unwrap_or(false) 60 | } 61 | } 62 | 63 | impl cmp::PartialEq for IndexedTransaction { 64 | fn eq(&self, other: &Self) -> bool { 65 | self.hash == other.hash 66 | } 67 | } 68 | 69 | impl cmp::Eq for IndexedTransaction {} 70 | 71 | impl Hash for IndexedTransaction { 72 | fn hash(&self, state: &mut H) { 73 | self.hash.hash(state); 74 | } 75 | } 76 | 77 | fn get_transaction_hash(transaction: &Transaction) -> Option { 78 | let mut buf = Vec::with_capacity(255); 79 | transaction.raw_data.as_ref()?.encode(&mut buf).ok()?; // won't fail? 80 | Some(sha256(&buf)) 81 | } 82 | -------------------------------------------------------------------------------- /keys/src/keypair.rs: -------------------------------------------------------------------------------- 1 | //! A KeyPair type is for generating and saving private/public key pairs. 2 | use std::fmt; 3 | 4 | use rand::rngs::OsRng; 5 | use libsecp256k1::{PublicKey, SecretKey}; 6 | 7 | use crate::address::Address; 8 | use crate::error::Error; 9 | use crate::private::Private; 10 | use crate::public::Public; 11 | 12 | /// A KeyPair combines a private key and its corresponding public key. 13 | #[derive(Debug, Hash, Clone)] 14 | pub struct KeyPair { 15 | private: Private, 16 | public: Public, 17 | } 18 | 19 | impl KeyPair { 20 | /// Returns private part of the keypair 21 | pub fn private(&self) -> &Private { 22 | &self.private 23 | } 24 | 25 | /// Returns public part of the keypair 26 | pub fn public(&self) -> &Public { 27 | &self.public 28 | } 29 | 30 | /// Returns public part of the keypair converted into Address 31 | pub fn address(&self) -> Address { 32 | Address::from_public(&self.public) 33 | } 34 | 35 | /// Construct key pair from private key. 36 | pub fn from_private(private: Private) -> Result { 37 | let public = Public::from_private(&private)?; 38 | Ok(KeyPair { private, public }) 39 | } 40 | 41 | fn from_keypair(sec: SecretKey, publ: PublicKey) -> Self { 42 | let mut pub_key = [0u8; 64]; 43 | pub_key[..].copy_from_slice(&publ.serialize()[1..]); 44 | 45 | KeyPair { 46 | private: Private::from(sec.serialize()), 47 | public: Public::from(pub_key), 48 | } 49 | } 50 | 51 | /// Generates a new random KeyPair. 52 | pub fn generate() -> Self { 53 | let mut rng = OsRng; 54 | let secret_key = SecretKey::random(&mut rng); 55 | let public_key = PublicKey::from_secret_key(&secret_key); 56 | 57 | KeyPair::from_keypair(secret_key, public_key) 58 | } 59 | } 60 | 61 | impl fmt::Display for KeyPair { 62 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 63 | writeln!(f, "private: {:}", &self.private)?; 64 | writeln!(f, "public: {:}", &self.public)?; 65 | write!(f, "address: {:}", &Address::from_public(&self.public)) 66 | } 67 | } 68 | 69 | #[cfg(test)] 70 | mod tests { 71 | use super::*; 72 | 73 | #[test] 74 | fn test_keypair_generate() { 75 | let key_pair = KeyPair::generate(); 76 | 77 | println!("keypair =>\n{:}", key_pair); 78 | assert_eq!(&Public::from_private(key_pair.private()).unwrap(), key_pair.public()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /manager/src/version_fork.rs: -------------------------------------------------------------------------------- 1 | //! Block version fork controller. 2 | 3 | use constants::block_version::{BlockVersion, ForkPolicy}; 4 | use state::keys; 5 | 6 | use super::Manager; 7 | 8 | /// Handle block version upgrade. 9 | /// 10 | /// NOTE: The implementation is very different from java-tron. 11 | /// 12 | /// In java-tron, version fork is handle by `ForkUtils.java` and `ForkController.java`. 13 | /// Each version in saved in DB as a bit vector, each bit represents an SR's block version status(downgrade or upgrade). 14 | /// `ForkController` accepts block and saves version status. 15 | /// 16 | /// Here, OpenTron saves an SR's block version status in Witness as `latest_block_version`, updated as recieving blocks. 17 | /// 18 | /// FIXME: If there's inconsistent when an SR downgrades it's block version? 19 | pub struct ForkController<'m> { 20 | manager: &'m Manager, 21 | } 22 | 23 | impl ForkController<'_> { 24 | pub fn new<'a>(manager: &'a Manager) -> ForkController<'a> { 25 | ForkController { manager } 26 | } 27 | 28 | pub fn pass_version(&self, version: BlockVersion) -> Result { 29 | match version.fork_policy() { 30 | ForkPolicy::AtBlock { block_number } => Ok(self.manager.latest_block_number() >= block_number), 31 | ForkPolicy::Old => { 32 | let active_wit_addrs = self.manager.get_active_witnesses(); 33 | let all_passed = active_wit_addrs 34 | .into_iter() 35 | .map(|addr| self.manager.state_db.must_get(&keys::Witness(addr))) 36 | .all(|wit| wit.latest_block_version >= version as _); 37 | Ok(all_passed) 38 | } 39 | ForkPolicy::New { 40 | timestamp, 41 | min_upgrade_percent, 42 | } => { 43 | let maintenance_interval = self 44 | .manager 45 | .state_db 46 | .must_get(&keys::ChainParameter::MaintenanceInterval); 47 | let hard_fork_ts = ((timestamp - 1) / maintenance_interval + 1) * maintenance_interval; 48 | 49 | if self.manager.latest_block_number() < hard_fork_ts { 50 | return Ok(false); 51 | } 52 | 53 | let active_wit_addrs = self.manager.get_active_witnesses(); 54 | let min_num_required = (active_wit_addrs.len() * min_upgrade_percent as usize) as f64 / 100.0; 55 | let num_passed = active_wit_addrs 56 | .into_iter() 57 | .map(|addr| self.manager.state_db.must_get(&keys::Witness(addr))) 58 | .map(|wit| wit.latest_block_version >= version as _) 59 | .count(); 60 | Ok(num_passed as f64 >= min_num_required) 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ztron/tests/mint.hex: -------------------------------------------------------------------------------- 1 | b96d8322196ce2cf925306d4522b6b9ee0cec4bb5d0e5c929fdd3ac6e7fb934a9d8024b5d6f111582d1eebf9badfcf771756fcd0c03c8efe22d118f118efc6998ad11d79c630886adbb64daa187912329ee7cf72a245ae9c36164d19c611cf3aa34bb52bc4321d79587d3f704d80f36b1c83394fce7e69b17c722a870b0b64e3c4ff313ab8cc3c92e5ea862d4204719b87ccf83e71db20ffacb8b099e4401613e7c9a36fbaefed4c203aaecf4bb78de91134da6946a45aca37952a56f66e095e03a01a231083854f31f48357895007ea214efcf2e32a9d8734851e262a3a3e45299535e88bef680b00197063c19ce9c8802c210a6502c6662a57f9ff9758e6cd4e7bb02cecf74b00727dba28a5e6d61055d7c40284cd29e302e5c936f8ce2a76337fdc8fc3e8fb20cbff1f1a8bb1d82b1c7d1bec4a02db0af4008e245019d19257b07a94e0295144ae9af870b4647d705b44da5d44f167d2c35befd5de1eac04000000000000000000000000000000000000000000000000000000000000000289770f5a3c151703aad5a401f7587fc90a11009f4cab710cdceed72c24e7719e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 2 | -------------------------------------------------------------------------------- /etc/conf.nile.toml: -------------------------------------------------------------------------------- 1 | log-level = 'info' 2 | log-file = '' 3 | 4 | [server] 5 | sync-check = false 6 | 7 | [storage] 8 | # related to run path 9 | data-dir = './data.nile/chaindb' 10 | engine = 'rocksdb' 11 | state-data-dir = './data.nile/statedb' 12 | state-cache-dir = './data.nile/cache' 13 | 14 | [chain] 15 | # related to current config file 16 | genesis = 'genesis.nile.json' 17 | p2p-version = 201910292 18 | 19 | # default: 259200_000 20 | proposal-expiration-duration = 600_000 21 | # block-producing-interval = '3s' 22 | 23 | [chain.parameter] 24 | # in ms, 10m 25 | maintenance-interval = 600_000 26 | # PrivateNet: true 27 | #allow-multisig = false 28 | # PrivateNet: true 29 | #allow-adaptive-energy = false 30 | # PrivateNet: true 31 | #allow-delegate-resource = false 32 | # PrivateNet: true 33 | #allow-duplicate-asset-names = false 34 | # The TVM upgrade 35 | # PrivateNet: true 36 | #allow-tvm = false 37 | # PrivateNet: true 38 | #allow-tvm-transfer-trc10-upgrade = false 39 | # PrivateNet: true 40 | #allow-tvm-constantinople-upgrade = false 41 | # PrivateNet: true 42 | #allow-tvm-solidity-059-upgrade = false 43 | # PrivateNet: true 44 | #allow-tvm-shielded-upgrade = false 45 | 46 | # Default: 100, PrivateNet: 10 47 | #energy-price = 100 48 | 49 | [graphql] 50 | enable = true 51 | endpoint = "0.0.0.0:3000" 52 | 53 | [protocol] 54 | seed-nodes = ['47.90.214.183:18888'] 55 | 56 | [protocol.discovery] 57 | enable = false 58 | persist = true 59 | # udp discovery 60 | endpoint = '0.0.0.0:18888' 61 | # 62 | # advertise-endpoint = '' 63 | active-nodes = [] 64 | 65 | [protocol.channel] 66 | enable = true 67 | enable-passive = false 68 | enable-active = true 69 | # 1 to 2000 70 | # 100 for java-tron 71 | sync-batch-size = 2000 72 | # tcp channel 73 | endpoint = '0.0.0.0:18888' 74 | advertised-endpoint = '' 75 | # connect in any case 76 | active-nodes = [ 77 | # "182.92.154.46:18888", 78 | "119.23.35.152:18888", 79 | "47.75.218.79:18888", 80 | "47.252.17.40:18888", 81 | "47.252.19.181:18888", 82 | "47.90.243.177:18888", 83 | "47.90.214.183:18888", 84 | "47.252.73.173:18888", 85 | "34.216.199.10:18888", 86 | "34.216.199.10:18888", 87 | ] 88 | # accept in any case 89 | passive-nodes = [] 90 | max-active-connections = 2 91 | 92 | [witness] 93 | private-key = "" 94 | 95 | [prometheus] 96 | endpoint = '0.0.0.0:23333' 97 | 98 | [rocksdb] 99 | # create-if-missing = true 100 | max-open-files = 40960 101 | 102 | # max-background-jobs = 8 103 | # max-sub-compactions = 3 104 | # max-manifest-file-size = "128MB" 105 | # wal-recovery-mode = 2 106 | # wal-dir = "/tmp/tron/store" 107 | # wal-ttl-seconds = 0 108 | # wal-size-limit = 0 109 | # enable-statistics = true 110 | # stats-dump-period = "10m" 111 | # compaction-readahead-size = 0 112 | [rocksdb.defaultcf] 113 | compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] 114 | -------------------------------------------------------------------------------- /etc/conf.local-test.toml: -------------------------------------------------------------------------------- 1 | log-level = 'info' 2 | log-file = '' 3 | 4 | [server] 5 | sync-check = false 6 | 7 | [storage] 8 | # related to run path 9 | data-dir = './data-testnet/chaindb' 10 | state-data-dir = './data-testnet/statedb' 11 | state-cache-dir = './data-testnet/cache' 12 | engine = 'rocksdb' 13 | 14 | [chain] 15 | # related to current config file 16 | genesis = 'genesis.local-test.json' 17 | p2p-version = 233333333 18 | 19 | # 3d 20 | proposal-expiration-duration = 1200_000 21 | # block-producing-interval = '3s' 22 | 23 | [chain.parameter] 24 | # in ms, 10min 25 | maintenance-interval = 600_000 26 | 27 | # Default: 100, PrivateNet: 10 28 | energy-price = 140 29 | # Default: 10 30 | bandwidth-price = 140 31 | 32 | 33 | # NOTE: All following are enabled by proposals. 34 | # PrivateNet: true 35 | allow-multisig = true 36 | # PrivateNet: true 37 | allow-adaptive-energy = true 38 | # PrivateNet: true 39 | allow-delegate-resource = true 40 | # PrivateNet: true 41 | allow-duplicate-asset-names = true 42 | # The TVM upgrade 43 | # PrivateNet: true 44 | allow-tvm = true 45 | # PrivateNet: true 46 | allow-tvm-transfer-trc10-upgrade = true 47 | # PrivateNet: true 48 | allow-tvm-constantinople-upgrade = true 49 | # PrivateNet: true 50 | allow-tvm-solidity-059-upgrade = true 51 | # PrivateNet: true 52 | allow-tvm-shielded-upgrade = true 53 | # PrivateNet: true 54 | # TODO: unimplimented 55 | allow-tvm-istanbul-upgrade = false 56 | 57 | [producer] 58 | enable = true 59 | 60 | [[producer.keypair]] 61 | address = "TPBMeAqZd5JfbomoMX8BPMttSyHx4Notrx" 62 | private-key = "e957181964f4a3d6c0257a0aa57a5e49ae10dd0a3ab9d12ec05f2fb58862cffc" 63 | 64 | [graphql] 65 | enable = true 66 | endpoint = "0.0.0.0:3000" 67 | 68 | [protocol] 69 | seed-nodes = [ 70 | ] 71 | 72 | [protocol.discovery] 73 | enable = true 74 | persist = true 75 | # udp discovery 76 | endpoint = '0.0.0.0:18888' 77 | # 78 | # advertise-endpoint = '' 79 | active-nodes = [] 80 | 81 | [protocol.channel] 82 | enable = true 83 | enable-passive = true 84 | enable-active = true 85 | sync-batch-size = 1000 86 | # tcp channel 87 | endpoint = '0.0.0.0:18888' 88 | advertised-endpoint = '' 89 | # connect in any case 90 | active-nodes = [ 91 | ] 92 | # accept in any case 93 | passive-nodes = [] 94 | max-active-connections = 1 95 | 96 | [witness] 97 | private-key = "" 98 | 99 | [prometheus] 100 | endpoint = '0.0.0.0:23333' 101 | 102 | [rocksdb] 103 | # create-if-missing = true 104 | max-open-files = 40960 105 | 106 | # max-background-jobs = 8 107 | # max-sub-compactions = 3 108 | # max-manifest-file-size = "128MB" 109 | # wal-recovery-mode = 2 110 | # wal-dir = "/tmp/tron/store" 111 | # wal-ttl-seconds = 0 112 | # wal-size-limit = 0 113 | # enable-statistics = true 114 | # stats-dump-period = "10m" 115 | # compaction-readahead-size = 0 116 | [rocksdb.defaultcf] 117 | compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] 118 | -------------------------------------------------------------------------------- /chain/src/indexed_header.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{ByteOrder, BE}; 2 | use crypto::sha256; 3 | use prost::Message; 4 | use proto::chain::BlockHeader; 5 | use proto::common::BlockId; 6 | use std::cmp; 7 | use types::H256; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct IndexedBlockHeader { 11 | pub hash: H256, 12 | pub raw: BlockHeader, 13 | } 14 | 15 | impl IndexedBlockHeader { 16 | pub fn new(hash: H256, header: BlockHeader) -> Self { 17 | IndexedBlockHeader { 18 | hash: hash, 19 | raw: header, 20 | } 21 | } 22 | 23 | /// Explicit conversion of the raw BlockHeader into IndexedBlockHeader. 24 | /// 25 | /// Hashes the contents of block header. 26 | pub fn from_raw(header: BlockHeader) -> Option { 27 | get_block_header_hash(&header).map(|hash| IndexedBlockHeader::new(hash, header)) 28 | } 29 | 30 | /// Create a dummy block header. 31 | pub fn dummy(number: i64, timestamp: i64) -> Self { 32 | let mut hash = H256::zero(); 33 | BE::write_u64(&mut hash.as_bytes_mut()[..8], number as u64); 34 | let mut inner = BlockHeader { 35 | raw_data: Some(Default::default()), 36 | ..Default::default() 37 | }; 38 | inner.raw_data.as_mut().unwrap().timestamp = timestamp; 39 | IndexedBlockHeader { hash, raw: inner } 40 | } 41 | 42 | pub fn number(&self) -> i64 { 43 | BE::read_u64(&self.hash.as_bytes()[..8]) as i64 44 | } 45 | 46 | pub fn timestamp(&self) -> i64 { 47 | self.raw.raw_data.as_ref().unwrap().timestamp 48 | } 49 | 50 | pub fn version(&self) -> i32 { 51 | self.raw.raw_data.as_ref().unwrap().version 52 | } 53 | 54 | pub fn parent_hash(&self) -> &[u8] { 55 | &self.raw.raw_data.as_ref().unwrap().parent_hash 56 | } 57 | 58 | pub fn merkle_root_hash(&self) -> &[u8] { 59 | &self.raw.raw_data.as_ref().unwrap().merkle_root_hash 60 | } 61 | 62 | pub fn witness(&self) -> &[u8] { 63 | &self.raw.raw_data.as_ref().unwrap().witness_address 64 | } 65 | 66 | pub fn block_id(&self) -> BlockId { 67 | BlockId { 68 | number: self.number(), 69 | hash: self.hash.as_bytes().to_vec(), 70 | } 71 | } 72 | 73 | pub fn verify(&self) -> bool { 74 | get_block_header_hash(&self.raw) 75 | .map(|hash| hash == self.hash) 76 | .unwrap_or(false) 77 | } 78 | } 79 | 80 | impl cmp::PartialEq for IndexedBlockHeader { 81 | fn eq(&self, other: &Self) -> bool { 82 | self.hash == other.hash 83 | } 84 | } 85 | 86 | fn get_block_header_hash(header: &BlockHeader) -> Option { 87 | let raw_header = header.raw_data.as_ref()?; 88 | let block_numer = raw_header.number; 89 | 90 | let mut buf: Vec = Vec::with_capacity(255); 91 | raw_header.encode(&mut buf).ok()?; // encode failure? 92 | 93 | let mut block_hash = sha256(&buf); 94 | BE::write_i64(&mut block_hash[..8], block_numer); 95 | Some(block_hash) 96 | } 97 | -------------------------------------------------------------------------------- /manager/src/executor/actuators/shielded.rs: -------------------------------------------------------------------------------- 1 | //! Shielded transfer, only available in nile testnet. 2 | //! This is a dummy implementation. 3 | 4 | use std::convert::TryFrom; 5 | 6 | use ::keys::Address; 7 | use log::warn; 8 | use proto::chain::transaction::Result as TransactionResult; 9 | use proto::contract as contract_pb; 10 | use proto::state::Account; 11 | use state::keys; 12 | 13 | use super::super::TransactionContext; 14 | use super::BuiltinContractExecutorExt; 15 | use crate::Manager; 16 | 17 | /// The TRZ token id. 18 | const SHIELDED_TOKEN_ID: i64 = 1000016; 19 | // TODO: This following 2 should be chain parameters. Never mind, this is a dead feature. 20 | const SHIELDED_TRANSACTION_FEE: i64 = 10_000_000; 21 | const SHIELDED_TRANSACTION_CREATE_ACCOUNT_FEE: i64 = 10_000_000; 22 | 23 | impl BuiltinContractExecutorExt for contract_pb::ShieldedTransferContract { 24 | fn validate(&self, manager: &Manager, ctx: &mut TransactionContext) -> Result<(), String> { 25 | if !self.transparent_from_address.is_empty() { 26 | let fee = self.fee(manager); 27 | ctx.contract_fee = fee; 28 | } 29 | Ok(()) 30 | } 31 | 32 | fn execute(&self, manager: &mut Manager, ctx: &mut TransactionContext) -> Result { 33 | if !self.transparent_from_address.is_empty() { 34 | let from_addr = Address::try_from(&self.transparent_from_address).unwrap(); 35 | let mut from_acct = manager.state_db.must_get(&keys::Account(from_addr)); 36 | 37 | from_acct 38 | .adjust_token_balance(SHIELDED_TOKEN_ID, -self.from_amount) 39 | .unwrap(); 40 | manager 41 | .add_token_to_blackhole(SHIELDED_TOKEN_ID, ctx.contract_fee) 42 | .unwrap(); 43 | ctx.contract_fee = 0; // in TRZ, not TRX 44 | 45 | manager.state_db.put_key(keys::Account(from_addr), from_acct).unwrap(); 46 | } else if !self.transparent_to_address.is_empty() { 47 | let to_addr = Address::try_from(&self.transparent_to_address).unwrap(); 48 | let maybe_to_acct = manager.state_db.get(&keys::Account(to_addr)).unwrap(); 49 | let mut to_acct = maybe_to_acct.unwrap_or_else(|| Account::new(manager.latest_block_timestamp())); 50 | to_acct.adjust_token_balance(SHIELDED_TOKEN_ID, self.to_amount).unwrap(); 51 | 52 | manager.state_db.put_key(keys::Account(to_addr), to_acct).unwrap(); 53 | } else { 54 | warn!("fake handling z to z shielded transfer"); 55 | } 56 | Ok(TransactionResult::success()) 57 | } 58 | 59 | fn fee(&self, manager: &Manager) -> i64 { 60 | if !self.transparent_to_address.is_empty() { 61 | let to_addr = Address::try_from(&self.transparent_to_address).unwrap(); 62 | if manager.state_db.get(&keys::Account(to_addr)).unwrap().is_none() { 63 | return SHIELDED_TRANSACTION_CREATE_ACCOUNT_FEE; 64 | } 65 | } 66 | SHIELDED_TRANSACTION_FEE 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tvm/src/precompile/helper.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | use types::{H160, H256, U256}; 3 | 4 | const WORD_SIZE: usize = 32; 5 | 6 | pub struct AbiArgIterator<'a> { 7 | data: &'a [u8], 8 | offset: usize, 9 | } 10 | 11 | impl<'a> AbiArgIterator<'a> { 12 | pub fn new<'b>(data: &'b [u8]) -> AbiArgIterator<'b> { 13 | AbiArgIterator { data, offset: 0 } 14 | } 15 | 16 | pub fn next_byte32(&mut self) -> Option<&'a [u8]> { 17 | if self.offset < self.data.len() { 18 | let ret = &self.data[self.offset..self.offset + WORD_SIZE]; 19 | self.offset += WORD_SIZE; 20 | Some(ret) 21 | } else { 22 | None 23 | } 24 | } 25 | 26 | pub fn next_words_as_bytes(&mut self, n: usize) -> Option<&'a [u8]> { 27 | if self.offset < self.data.len() { 28 | let ret = &self.data[self.offset..self.offset + n * WORD_SIZE]; 29 | self.offset += n * WORD_SIZE; 30 | Some(ret) 31 | } else { 32 | None 33 | } 34 | } 35 | 36 | pub fn next_u256(&mut self) -> Option { 37 | self.next_byte32().map(U256::from_big_endian) 38 | } 39 | 40 | pub fn next_h256(&mut self) -> Option { 41 | self.next_byte32().map(H256::from_slice) 42 | } 43 | 44 | pub fn next_h160(&mut self) -> Option { 45 | self.next_h256().map(From::from) 46 | } 47 | 48 | pub fn next_bytes(&mut self) -> Option<&'a [u8]> { 49 | let local_offset: usize = self.next_u256()?.try_into().ok()?; 50 | 51 | let size: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 52 | .try_into() 53 | .ok()?; 54 | Some(&self.data[local_offset + WORD_SIZE..local_offset + WORD_SIZE + size]) 55 | } 56 | 57 | pub fn next_array_of_bytes(&mut self) -> Option> { 58 | // memory offset 59 | let mut local_offset: usize = self.next_u256()?.try_into().ok()?; 60 | 61 | if local_offset < self.data.len() { 62 | let len: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 63 | .try_into() 64 | .ok()?; 65 | local_offset += WORD_SIZE; 66 | 67 | let mut inner = AbiArgIterator::new(&self.data[local_offset..]); 68 | (0..len).map(|_| inner.next_bytes()).collect() 69 | } else { 70 | Some(vec![]) 71 | } 72 | } 73 | 74 | pub fn next_array_of_byte32(&mut self) -> Option> { 75 | // memory offset 76 | let mut local_offset: usize = self.next_u256()?.try_into().ok()?; 77 | 78 | if local_offset < self.data.len() { 79 | let len: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 80 | .try_into() 81 | .ok()?; 82 | local_offset += WORD_SIZE; 83 | 84 | let mut inner = AbiArgIterator::new(&self.data[local_offset..]); 85 | (0..len).map(|_| inner.next_byte32()).collect() 86 | } else { 87 | Some(vec![]) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /proto/proto/common.proto: -------------------------------------------------------------------------------- 1 | // Protobuf shared by all the other. 2 | syntax = "proto3"; 3 | 4 | package proto.common; 5 | 6 | // for discover, handshake, channel 7 | 8 | message Endpoint { 9 | // type changed: bytes 10 | string address = 1; 11 | int32 port = 2; 12 | bytes node_id = 3; 13 | } 14 | 15 | message BlockId { 16 | bytes hash = 1; 17 | int64 number = 2; 18 | } 19 | 20 | enum ResourceCode { 21 | BANDWIDTH = 0x00; 22 | ENERGY = 0x01; 23 | } 24 | 25 | // for contract 26 | 27 | enum AccountType { 28 | Normal = 0; 29 | AssetIssue = 1; 30 | Contract = 2; 31 | } 32 | 33 | message Vote { 34 | bytes vote_address = 1; 35 | int64 vote_count = 2; 36 | } 37 | 38 | message SmartContract { 39 | message ABI { 40 | enum EntryType { 41 | UnknownEntryType = 0; 42 | Constructor = 1; 43 | Function = 2; 44 | Event = 3; 45 | // Fallback functions are executed whenever a particular contract receives 46 | // plain Ether without any other data associated with the transaction. 47 | Fallback = 4; 48 | // Added in 4.1.2, for Solidity 0.6.0 49 | Receive = 5; 50 | } 51 | message Param { 52 | // This will cause the respective arguments to be searched for. 53 | // If arrays (including string and bytes) are used as indexed arguments, 54 | // the Keccak-256 hash of it is stored as topic instead. 55 | bool indexed = 1; 56 | string name = 2; 57 | string type = 3; 58 | // SolidityType type = 3; 59 | } 60 | enum StateMutabilityType { 61 | UnknownStateMutabilityType = 0; 62 | // With pure you cannot access the contract storage. 63 | // e.g. utility libraries. 64 | Pure = 1; 65 | // With view you cannot modify the contract storage, but you can access the storage. 66 | // e.g. contract getters. 67 | View = 2; 68 | Nonpayable = 3; 69 | Payable = 4; 70 | } 71 | message Entry { 72 | // The event was declared as `anonymous` 73 | bool anonymous = 1; 74 | // Replaced by view and pure. 75 | bool constant = 2; 76 | string name = 3; 77 | repeated Param inputs = 4; 78 | repeated Param outputs = 5; 79 | EntryType type = 6; 80 | bool payable = 7; 81 | StateMutabilityType state_mutability = 8; 82 | } 83 | // renamed: entrys 84 | repeated Entry entries = 1; 85 | } 86 | 87 | bytes origin_address = 1; 88 | bytes contract_address = 2; 89 | ABI abi = 3; 90 | bytes bytecode = 4; 91 | int64 call_value = 5; 92 | int64 consume_user_energy_percent = 6; 93 | string name = 7; 94 | int64 origin_energy_limit = 8; 95 | bytes code_hash = 9; 96 | // When smart contract is created by a trigger smart contract call. 97 | // renamed: trx_hash 98 | bytes txn_hash = 10; 99 | } 100 | 101 | message Permission { 102 | enum PermissionType { 103 | Owner = 0; 104 | Witness = 1; 105 | Active = 2; 106 | } 107 | message Key { 108 | bytes address = 1; 109 | int64 weight = 2; 110 | } 111 | 112 | PermissionType type = 1; 113 | // Owner id=0, Witness id=1, Active id starts by 2 114 | int32 id = 2; 115 | string name = 3; 116 | int64 threshold = 4; 117 | int32 parent_id = 5; 118 | // 1 bit for 1 contract type 119 | bytes operations = 6; 120 | repeated Key keys = 7; 121 | } 122 | -------------------------------------------------------------------------------- /tvm/src/precompile/alt_bn128.rs: -------------------------------------------------------------------------------- 1 | pub fn ecadd(input: &[u8]) -> Option> { 2 | use bn::{AffineG1, Fq, Group, G1}; 3 | 4 | let words: Vec<_> = input.chunks(32).collect(); 5 | 6 | let x1 = Fq::from_slice(words[0]).ok()?; 7 | let y1 = Fq::from_slice(words[1]).ok()?; 8 | 9 | let x2 = Fq::from_slice(words[2]).ok()?; 10 | let y2 = Fq::from_slice(words[3]).ok()?; 11 | 12 | let p1 = if x1 == Fq::zero() && y1 == Fq::zero() { 13 | G1::zero() 14 | } else { 15 | AffineG1::new(x1, y1).ok()?.into() 16 | }; 17 | let p2 = if x2 == Fq::zero() && y2 == Fq::zero() { 18 | G1::zero() 19 | } else { 20 | AffineG1::new(x2, y2).ok()?.into() 21 | }; 22 | 23 | let mut output = vec![0u8; 64]; 24 | if let Some(ret) = AffineG1::from_jacobian(p1 + p2) { 25 | ret.x().to_big_endian(&mut output[0..32]).unwrap(); 26 | ret.y().to_big_endian(&mut output[32..64]).unwrap(); 27 | Some(output) 28 | } else { 29 | None 30 | } 31 | } 32 | 33 | pub fn ecmul(input: &[u8]) -> Option> { 34 | use bn::{AffineG1, Fq, Fr, Group, G1}; 35 | 36 | let words: Vec<_> = input.chunks(32).collect(); 37 | 38 | let x1 = Fq::from_slice(words[0]).ok()?; 39 | let y1 = Fq::from_slice(words[1]).ok()?; 40 | 41 | let fr = Fr::from_slice(words[2]).ok()?; 42 | 43 | let p = if x1 == Fq::zero() && y1 == Fq::zero() { 44 | G1::zero() 45 | } else { 46 | AffineG1::new(x1, y1).ok()?.into() 47 | }; 48 | 49 | let mut output = vec![0u8; 64]; 50 | if let Some(ret) = AffineG1::from_jacobian(p * fr) { 51 | ret.x().to_big_endian(&mut output[0..32]).unwrap(); 52 | ret.y().to_big_endian(&mut output[32..64]).unwrap(); 53 | Some(output) 54 | } else { 55 | None 56 | } 57 | } 58 | 59 | pub fn ecpairing(input: &[u8]) -> Option> { 60 | use bn::{pairing, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; 61 | use types::U256; 62 | 63 | const PAIR_SIZE: usize = 192; 64 | 65 | fn read_one_pair(input: &[u8]) -> Option<(G1, G2)> { 66 | let words: Vec<_> = input.chunks(32).collect(); 67 | 68 | let ax = Fq::from_slice(words[0]).ok()?; 69 | let ay = Fq::from_slice(words[1]).ok()?; 70 | let bay = Fq::from_slice(words[2]).ok()?; 71 | let bax = Fq::from_slice(words[3]).ok()?; 72 | let bby = Fq::from_slice(words[4]).ok()?; 73 | let bbx = Fq::from_slice(words[5]).ok()?; 74 | 75 | let ba = Fq2::new(bax, bay); 76 | let bb = Fq2::new(bbx, bby); 77 | 78 | let b = if ba.is_zero() && bb.is_zero() { 79 | G2::zero() 80 | } else { 81 | AffineG2::new(ba, bb).ok()?.into() 82 | }; 83 | let a = if ax.is_zero() && ay.is_zero() { 84 | G1::zero() 85 | } else { 86 | AffineG1::new(ax, ay).ok()?.into() 87 | }; 88 | 89 | Some((a, b)) 90 | } 91 | 92 | // input len is not a multiple of PAIR_SIZE 93 | if input.len() == 0 || input.len() % PAIR_SIZE != 0 { 94 | return None; 95 | } 96 | 97 | let mut acc = Gt::one(); 98 | for pair in input.chunks(PAIR_SIZE) { 99 | let (a, b) = read_one_pair(pair)?; 100 | acc = acc * pairing(a, b); 101 | } 102 | 103 | let result = if acc == Gt::one() { U256::one() } else { U256::zero() }; 104 | 105 | let mut ret = vec![0u8; 32]; 106 | result.to_big_endian(&mut ret[..]); 107 | Some(ret) 108 | } 109 | -------------------------------------------------------------------------------- /merkle-tree/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod merkle_tree; 2 | mod tree; 3 | use types::H256; 4 | 5 | pub use crate::merkle_tree::MerkleTree; 6 | 7 | /// A hashable type 8 | pub trait MerkleHasher { 9 | type Input; 10 | // type Output; 11 | fn hash(input: &Self::Input) -> H256; 12 | 13 | fn hash_nodes(left: &H256, right: &H256) -> H256; 14 | 15 | fn hash_empty() -> H256 { 16 | H256::zero() 17 | } 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | use sha2::{Digest, Sha256}; 24 | use std::mem; 25 | 26 | pub struct BytesSha256Hasher; 27 | 28 | impl MerkleHasher for BytesSha256Hasher { 29 | type Input = Vec; 30 | 31 | fn hash(input: &Self::Input) -> H256 { 32 | let mut sha256 = Sha256::new(); 33 | sha256.update(input); 34 | unsafe { mem::transmute(sha256.finalize()) } 35 | } 36 | 37 | fn hash_nodes(left: &H256, right: &H256) -> H256 { 38 | let result = Sha256::new().chain(left.as_bytes()).chain(right.as_bytes()).finalize(); 39 | unsafe { mem::transmute(result) } 40 | } 41 | } 42 | 43 | #[test] 44 | fn empty_tree() { 45 | let list: Vec> = vec![]; 46 | let tree: MerkleTree = MerkleTree::from_vec(list); 47 | assert_eq!(&H256::zero(), tree.root_hash()); 48 | } 49 | 50 | #[test] 51 | fn tree_with_one_node() { 52 | let list: Vec> = vec![b"\x00\x00\x00\x00".to_vec()]; 53 | let tree: MerkleTree = MerkleTree::from_vec(list); 54 | // sha256 of "0x00_00_00_00" 55 | assert_eq!( 56 | &"df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119" 57 | .parse::() 58 | .unwrap(), 59 | tree.root_hash() 60 | ); 61 | } 62 | 63 | #[test] 64 | fn tree_with_two_nodes() { 65 | let list: Vec> = vec![b"\x00\x00\x00\x00".to_vec(), b"\x00\x00\x00\x01".to_vec()]; 66 | let tree: MerkleTree = MerkleTree::from_vec(list); 67 | // hashlib.sha256( 68 | // bytes.fromhex( 69 | // 'df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119' + # 00_00_00_00 70 | // 'b40711a88c7039756fb8a73827eabe2c0fe5a0346ca7e0a104adc0fc764f528d' # 00_00_00_01 71 | // )).hexdigest() 72 | assert_eq!( 73 | &"430ebda8b2441cf6a796f7f2a9b3377ae2fc8b23fe022fc018bed864b0fa1815" 74 | .parse::() 75 | .unwrap(), 76 | tree.root_hash() 77 | ); 78 | } 79 | 80 | #[test] 81 | fn tree_with_three_nodes() { 82 | let list: Vec> = vec![ 83 | b"\x00\x00\x00\x00".to_vec(), 84 | b"\x00\x00\x00\x01".to_vec(), 85 | b"\x00\x00\x00\x02".to_vec(), 86 | ]; 87 | let tree: MerkleTree = MerkleTree::from_vec(list); 88 | // hashlib.sha256( 89 | // bytes.fromhex( 90 | // '430ebda8b2441cf6a796f7f2a9b3377ae2fc8b23fe022fc018bed864b0fa1815' + # above 91 | // '433ebf5bc03dffa38536673207a21281612cef5faa9bc7a4d5b9be2fdb12cf1a' # 00_00_00_02 92 | // )).hexdigest() 93 | assert_eq!( 94 | &"baab99a32bb15f1d10b9dd6958f98a729e8d237207b7d8b9e7789e382834d1eb" 95 | .parse::() 96 | .unwrap(), 97 | tree.root_hash() 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /proto/src/proto.channel.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, PartialEq, ::prost::Message)] 2 | pub struct HandshakeHello { 3 | #[prost(message, optional, tag="1")] 4 | pub from: ::core::option::Option, 5 | #[prost(int32, tag="2")] 6 | pub version: i32, 7 | #[prost(int64, tag="3")] 8 | pub timestamp: i64, 9 | /// number=0 10 | #[prost(message, optional, tag="4")] 11 | pub genesis_block_id: ::core::option::Option, 12 | #[prost(message, optional, tag="5")] 13 | pub solid_block_id: ::core::option::Option, 14 | #[prost(message, optional, tag="6")] 15 | pub head_block_id: ::core::option::Option, 16 | #[prost(bytes="vec", tag="7")] 17 | pub address: ::prost::alloc::vec::Vec, 18 | #[prost(bytes="vec", tag="8")] 19 | pub signature: ::prost::alloc::vec::Vec, 20 | } 21 | #[derive(Clone, PartialEq, ::prost::Message)] 22 | pub struct HandshakeDisconnect { 23 | #[prost(enumeration="ReasonCode", tag="1")] 24 | pub reason: i32, 25 | } 26 | #[derive(Clone, PartialEq, ::prost::Message)] 27 | pub struct ChainInventory { 28 | #[prost(message, repeated, tag="1")] 29 | pub ids: ::prost::alloc::vec::Vec, 30 | #[prost(int64, tag="2")] 31 | pub remain_num: i64, 32 | } 33 | #[derive(Clone, PartialEq, ::prost::Message)] 34 | pub struct BlockInventory { 35 | #[prost(message, repeated, tag="1")] 36 | pub ids: ::prost::alloc::vec::Vec, 37 | #[prost(enumeration="block_inventory::Type", tag="2")] 38 | pub r#type: i32, 39 | } 40 | /// Nested message and enum types in `BlockInventory`. 41 | pub mod block_inventory { 42 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 43 | #[repr(i32)] 44 | pub enum Type { 45 | Sync = 0, 46 | /// unused 47 | Advtise = 1, 48 | /// unused 49 | Fetch = 2, 50 | } 51 | } 52 | #[derive(Clone, PartialEq, ::prost::Message)] 53 | pub struct Inventory { 54 | #[prost(enumeration="inventory::Type", tag="1")] 55 | pub r#type: i32, 56 | #[prost(bytes="vec", repeated, tag="2")] 57 | pub ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, 58 | } 59 | /// Nested message and enum types in `Inventory`. 60 | pub mod inventory { 61 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 62 | #[repr(i32)] 63 | pub enum Type { 64 | Trx = 0, 65 | Block = 1, 66 | } 67 | } 68 | #[derive(Clone, PartialEq, ::prost::Message)] 69 | pub struct Transactions { 70 | #[prost(message, repeated, tag="1")] 71 | pub transactions: ::prost::alloc::vec::Vec, 72 | } 73 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] 74 | #[repr(i32)] 75 | pub enum ReasonCode { 76 | Requested = 0, 77 | BadProtocol = 2, 78 | TooManyPeers = 4, 79 | DuplicatePeer = 5, 80 | IncompatibleProtocol = 6, 81 | NullIdentity = 7, 82 | PeerQuiting = 8, 83 | UnexpectedIdentity = 9, 84 | LocalIdentity = 10, 85 | PingTimeout = 11, 86 | UserReason = 16, 87 | Reset = 17, 88 | SyncFail = 18, 89 | FetchFail = 19, 90 | BadTx = 20, 91 | BadBlock = 21, 92 | Forked = 22, 93 | Unlinkable = 23, 94 | IncompatibleVersion = 24, 95 | IncompatibleChain = 25, 96 | TimeOut = 32, 97 | ConnectFail = 33, 98 | TooManyPeersWithSameIp = 34, 99 | Unknown = 255, 100 | } 101 | -------------------------------------------------------------------------------- /constants/src/lib.rs: -------------------------------------------------------------------------------- 1 | //* Chain constants. 2 | 3 | use block_version::BlockVersion; 4 | 5 | pub mod block_version; 6 | 7 | /// Current block version for produced block. 8 | pub const CURRENT_BLOCK_VERSION: BlockVersion = BlockVersion::GreatVoyage4_0_1; 9 | 10 | // * Block Produce. 11 | 12 | /// Will postpone txns if block size exceeds 2MiB. 13 | /// So in theory, max txns/block is around 7700, max tps is around 2500. 14 | pub const MAX_BLOCK_SIZE: usize = 2_000_000; 15 | 16 | // 3s, in ms. 17 | pub const BLOCK_PRODUCING_INTERVAL: i64 = 3_000; 18 | 19 | // 50% 20 | pub const BLOCK_PRODUCE_TIMEOUT_PERCENT: i64 = 50; 21 | 22 | /// Max block size in channel protocol handler. 23 | pub const MAX_ACCEPTABLE_BLOCK_SIZE: usize = MAX_BLOCK_SIZE + 1000; 24 | 25 | pub const FREE_BANDWIDTH: i64 = 5000; 26 | 27 | //* Witness and block producing. 28 | pub const MAX_NUM_OF_ACTIVE_WITNESSES: usize = 27; 29 | pub const MAX_NUM_OF_STANDBY_WITNESSES: usize = 127; 30 | 31 | // 27 * 70% = 18.9, so a solid block is one verified by 19 witnesses. 32 | pub const SOLID_THRESHOLD_PERCENT: usize = 70; 33 | 34 | // ChainConstant: getMaintenanceSkipSlots, MAINTENANCE_SKIP_SLOTS 35 | pub const NUM_OF_SKIPPED_SLOTS_IN_MAINTENANCE: usize = 2; 36 | 37 | // An SR should produce this much blocks then next. 38 | pub const NUM_OF_CONSECUTIVE_BLOCKS_PER_ROUND: usize = 1; 39 | 40 | /// Renamed: WitnessAllowanceFrozenTime 41 | pub const NUM_OF_FROZEN_DAYS_FOR_WITNESS_ALLOWANCE: i64 = 1; 42 | 43 | /// Percent of block reward paid to witness. 44 | pub const DEFAULT_BROKERAGE_RATE: i32 = 20; 45 | 46 | /// Renamed: BLOCK_FILLED_SLOTS_NUMBER 47 | pub const NUM_OF_BLOCK_FILLED_SLOTS: usize = 128; 48 | 49 | //* Transactions 50 | 51 | /// 500KB 52 | pub const MAX_TRANSACTION_SIZE: usize = 500 * 1024; 53 | 54 | pub const MAX_TRANSACTION_RESULT_SIZE: usize = 64; 55 | 56 | /// Max number of votes in a `VoteWitness` is 30. 57 | pub const MAX_NUM_OF_VOTES: usize = 30; 58 | 59 | /// 1d, in ms. 60 | pub const MAX_TRANSACTION_EXPIRATION: i64 = 24 * 60 * 60 * 1_000; 61 | 62 | pub const DEFAULT_ORIGIN_ENERGY_LIMIT: usize = 10_000_000; 63 | 64 | pub const MAX_NUM_OF_FROZEN_DAYS_FOR_RESOURCE: i64 = 3; 65 | pub const MIN_NUM_OF_FROZEN_DAYS_FOR_RESOURCE: i64 = 3; 66 | 67 | /// Max number of `FronzenSupply` in AssetIssue. 68 | pub const MAX_NUM_OF_FROZEN_SUPPLIES_IN_ASSET_ISSUE: usize = 10; 69 | 70 | pub const MAX_NUM_OF_FROZEN_DAYS_IN_ASSET_ISSUE: i64 = 3652; 71 | pub const MIN_NUM_OF_FROZEN_DAYS_IN_ASSET_ISSUE: i64 = 1; 72 | 73 | /// Renamed: OneDayNetLimit, restrict both free_asset_bandwidth_limit and public_free_asset_bandwidth_limit. 74 | pub const MAX_FREE_BANDWIDTH_IN_ASSET_ISSUE: i64 = 57_600_000_000; 75 | 76 | // Renamed: ExchangeBalanceLimit 77 | pub const MAX_EXCHANGE_BALANCE: usize = 1_000_000_000_000_000; 78 | 79 | // 1d, in ms. 80 | pub const RESOURCE_WINDOW_SIZE: i64 = 24 * 3600 * 1000; 81 | /// Precision used in resource calculation. 82 | pub const RESOURCE_PRECISION: i64 = 1_000_000; 83 | 84 | // * Adaptive Energy 85 | // if TotalEnergyAverageUsage > TotalEnergyTargetLimit: 86 | // decrease TotalEnergyCurrentLimit to 99/100 87 | // else 88 | // increase TotalEnergyCurrentLimit to 1000/999 89 | // 90 | // FYI: Limit / Weight = price 91 | pub const ADAPTIVE_ENERGY_DECREASE_RATE_NUMERATOR: i64 = 99; 92 | pub const ADAPTIVE_ENERGY_DECREASE_RATE_DENOMINATOR: i64 = 100; 93 | 94 | pub const ADAPTIVE_ENERGY_INCREASE_RATE_NUMERATOR: i64 = 1000; 95 | pub const ADAPTIVE_ENERGY_INCREASE_RATE_DENOMINATOR: i64 = 999; 96 | 97 | // * Account 98 | 99 | pub const MAX_NUM_OF_ACTIVE_PERMISSIONS: usize = 8; 100 | 101 | // Renamed: TotalSignNum 102 | pub const MAX_NUM_OF_KEYS_IN_PERMISSION: usize = 5; 103 | -------------------------------------------------------------------------------- /docs/versions.md: -------------------------------------------------------------------------------- 1 | # Release Versions of Java-Tron 2 | 3 | ref: `block_version.rs`. The following versions are related to the block version in block header. 4 | 5 | ```rust 6 | /// Block versions. These versions match version names on github release page(or PR numbers). 7 | #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] 8 | pub enum BlockVersion { 9 | /// Also applies to all blocks before around mainnet#2300000. 10 | Genesis = 0, 11 | /// First introduce block_version, PR #1290. 12 | Unknown1290 = 1, 13 | // PR #1442 14 | Odyssey3_0_1 = 2, 15 | // PR #1485 16 | Odyssey3_1_0 = 3, 17 | /// Special Check after block #4727890 (enery.limit.block.num). 18 | /// When block.version == 5, 19 | /// it makes block use new energy to handle transaction when block number >= 4727890L. 20 | /// Otherwise version !=5, skip. 21 | /// 22 | /// - Support Of Resource Delegation. 23 | /// - UpdateEnergyLimitContract 24 | /// - TotalEnergyLimit 25 | /// - AllowTvmTransferTrc10Upgrade 26 | /// - CALLTOKEN, TOKENBALANCE, CALLTOKENVALUE, CALLTOKENID 27 | /// 28 | /// Renamed: ENERGY_LIMIT 29 | Odyssey3_2 = 5, 30 | /// - Deprecates `TotalEnergyLimit` 31 | /// - Add `TotalCurrentEnergyLimit` 32 | Odyssey3_2_2 = 6, 33 | /// - AllowMultisig - introduce user permission 34 | /// - AllowAdaptiveEnergy 35 | /// - UpdateAccountPermissionFee 36 | /// - MultisigFee 37 | Odyssey3_5 = 7, 38 | /// - AllowProtoFilterNum 39 | // - useless 40 | /// - AllowAccountStateRoot 41 | // - never used, but there're some blocks generated filled with the field 42 | /// - AllowTvmConstantinopleUpgrade 43 | /// - ClearABI 44 | /// - reject delegate resource to contract address 45 | /// - Save runtime code from deploy code 46 | /// - SHL, SHR, SAR, fake CREATE2, EXTCODEHASH 47 | /// - Introduce TransferException 48 | Odyssey3_6_0 = 8, 49 | /// - AllowTvmSolidity059Upgrade 50 | /// - create account while transfer TRX/TRC10 51 | /// - batchvalidatesig, validatemultisig 52 | /// - ISCONTRACT 53 | /// - AdaptiveResourceLimitTargetRatio 54 | /// - AdaptiveResourceLimitMultiplier 55 | /// - AllowChangeDelegation 56 | /// - StandbyWitnessPayPerBlock 57 | Odyssey3_6_5 = 9, 58 | /// - ForbidTransferToContract 59 | Odyssey3_6_6 = 10, 60 | // NOTE: This version has only non-core API changes. Should not be a version fork. 61 | /// On Nile testnet, this is the `AllowShieldedTransaction` fork. 62 | /// 63 | /// See-also: https://github.com/tronprotocol/java-tron/pull/3372 64 | /// 65 | /// See-also: block 1628391 of Nile testnet 66 | Odyssey3_7 = 15, 67 | /// Shielded TVM precompiles. 68 | /// 69 | /// - support AllowTvmShieldedUpgrade config 70 | GreatVoyage4_0_0 = 16, 71 | /// First hard fork based on timestamp. Fork at 1596780000_000, at least 22 SRs. 72 | /// 73 | /// See-also: https://github.com/tronprotocol/java-tron/pull/3314 74 | /// 75 | /// - support AllowTvmShieldedUpgrade proposal 76 | GreatVoyage4_0_1 = 17, 77 | /// - AllowPbft 78 | /// - AllowTvmIstanbulUpgrade 79 | /// - AllowMarketTransaction 80 | /// - MarketSellFee 81 | /// - MarketCancelFee 82 | GreatVoyage4_1_0 = 19, 83 | /// - MaxFeeLimit 84 | /// - AllowTransactionFeePool 85 | /// - AllowBlackholeOptimization 86 | GreatVoyage4_1_2 = 20, 87 | /// Freezing for energy, bandwidth, and TP(TRON Vote Power). 88 | /// Freeze instruction for TVM 89 | GreatVoyage4_2_0 = 21, 90 | /// Solidity_0.8.4 suppot. 91 | /// Vote in TVM. 92 | /// Bandwidth handling, more proposals. 93 | GreatVoyage4_3_0 = 22, 94 | } 95 | ``` 96 | -------------------------------------------------------------------------------- /etc/conf.toml: -------------------------------------------------------------------------------- 1 | log-level = 'info' 2 | log-file = '' 3 | 4 | [server] 5 | sync-check = false 6 | 7 | [storage] 8 | # related to run path 9 | data-dir = './data/chaindb' 10 | state-data-dir = './data/statedb' 11 | state-cache-dir = './data/cache' 12 | engine = 'rocksdb' 13 | 14 | [chain] 15 | # related to current config file 16 | genesis = 'genesis.json' 17 | p2p-version = 11111 18 | 19 | # 3d 20 | proposal-expiration-duration = 259200_000 21 | # block-producing-interval = '3s' 22 | 23 | [chain.parameter] 24 | # in ms, 6h 25 | maintenance-interval = 21600_000 26 | 27 | # NOTE: All following are enabled by proposals. 28 | # PrivateNet: true 29 | #allow-multisig = false 30 | # PrivateNet: true 31 | #allow-adaptive-energy = false 32 | # PrivateNet: true 33 | #allow-delegate-resource = false 34 | # PrivateNet: true 35 | #allow-duplicate-asset-names = false 36 | # The TVM upgrade 37 | # PrivateNet: true 38 | #allow-tvm = false 39 | # PrivateNet: true 40 | #allow-tvm-transfer-trc10-upgrade = false 41 | # PrivateNet: true 42 | #allow-tvm-constantinople-upgrade = false 43 | # PrivateNet: true 44 | #allow-tvm-solidity-059-upgrade = false 45 | # PrivateNet: true 46 | #allow-tvm-shielded-upgrade = false 47 | 48 | # Default: 100, PrivateNet: 10 49 | #energy-price = 100 50 | 51 | [graphql] 52 | enable = true 53 | endpoint = "0.0.0.0:3000" 54 | 55 | [protocol] 56 | # official nodes 57 | seed-nodes = [ 58 | '54.236.37.243:18888', 59 | '52.53.189.99:18888', 60 | '18.196.99.16:18888', 61 | '34.253.187.192:18888', 62 | '52.56.56.149:18888', 63 | '35.180.51.163:18888', 64 | '54.252.224.209:18888', 65 | '18.228.15.36:18888', 66 | '52.15.93.92:18888', 67 | '34.220.77.106:18888', 68 | '13.127.47.162:18888', 69 | '13.124.62.58:18888', 70 | '13.229.128.108:18888', 71 | '35.182.37.246:18888', 72 | '34.200.228.125:18888', 73 | '18.220.232.201:18888', 74 | '13.57.30.186:18888', 75 | '35.165.103.105:18888', 76 | '18.184.238.21:18888', 77 | '34.250.140.143:18888', 78 | '35.176.192.130:18888', 79 | '52.47.197.188:18888', 80 | '52.62.210.100:18888', 81 | '13.231.4.243:18888', 82 | '18.231.76.29:18888', 83 | '35.154.90.144:18888', 84 | '13.125.210.234:18888', 85 | '13.250.40.82:18888', 86 | '35.183.101.48:18888', 87 | ] 88 | 89 | [protocol.discovery] 90 | enable = true 91 | persist = true 92 | # udp discovery 93 | endpoint = '0.0.0.0:18888' 94 | # 95 | # advertise-endpoint = '' 96 | active-nodes = [] 97 | 98 | [protocol.channel] 99 | enable = true 100 | enable-passive = true 101 | enable-active = true 102 | sync-batch-size = 1000 103 | # tcp channel 104 | endpoint = '0.0.0.0:18888' 105 | advertised-endpoint = '' 106 | # connect in any case 107 | active-nodes = [ 108 | "47.75.249.4:18888", 109 | "47.75.128.222:18888", 110 | "47.52.59.134:18888", 111 | "47.75.38.234:18888", 112 | "47.52.23.94:18888", 113 | "47.52.72.180:18888", 114 | "47.75.74.31:18888", 115 | "47.75.77.31:18888", 116 | "47.75.65.115:18888", 117 | ] 118 | # accept in any case 119 | passive-nodes = [] 120 | max-active-connections = 1 121 | 122 | [witness] 123 | private-key = "" 124 | 125 | [prometheus] 126 | endpoint = '0.0.0.0:23333' 127 | 128 | [rocksdb] 129 | # create-if-missing = true 130 | max-open-files = 40960 131 | 132 | # max-background-jobs = 8 133 | # max-sub-compactions = 3 134 | # max-manifest-file-size = "128MB" 135 | # wal-recovery-mode = 2 136 | # wal-dir = "/tmp/tron/store" 137 | # wal-ttl-seconds = 0 138 | # wal-size-limit = 0 139 | # enable-statistics = true 140 | # stats-dump-period = "10m" 141 | # compaction-readahead-size = 0 142 | [rocksdb.defaultcf] 143 | compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] 144 | -------------------------------------------------------------------------------- /cli/src/system.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use itertools::Itertools; 3 | use keys::Address; 4 | use proto::chain::transaction::Contract; 5 | use proto::contract as contract_pb; 6 | 7 | pub fn main(matches: &ArgMatches) -> Option { 8 | match matches.subcommand() { 9 | ("freeze", Some(arg_matches)) => freeze(arg_matches), 10 | ("unfreeze", Some(arg_matches)) => unfreeze(arg_matches), 11 | ("vote", Some(arg_matches)) => vote(arg_matches), 12 | ("withdraw", Some(arg_matches)) => withdraw(arg_matches), 13 | _ => unreachable!("in cli.yml; qed"), 14 | } 15 | } 16 | 17 | fn freeze(matches: &ArgMatches) -> Option { 18 | use proto::common::ResourceCode as ResourceType; 19 | 20 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 21 | let to: Address = matches.value_of("RECIPIENT")?.parse().ok()?; 22 | let amount = crate::util::parse_amount_with_currency(matches.value_of("AMOUNT")?, "TRX", 6)?; 23 | 24 | let resource_type = match matches.value_of("type") { 25 | Some("bandwidth") => ResourceType::Bandwidth, 26 | Some("energy") => ResourceType::Energy, 27 | _ => unreachable!("checks values in clap; qed"), 28 | }; 29 | 30 | let inner = contract_pb::FreezeBalanceContract { 31 | owner_address: from.as_bytes().into(), 32 | frozen_balance: amount, 33 | frozen_duration: 3, 34 | resource: resource_type as i32, 35 | receiver_address: if from == to { vec![] } else { to.as_bytes().into() }, 36 | }; 37 | 38 | Some(inner.into()) 39 | } 40 | 41 | fn unfreeze(matches: &ArgMatches) -> Option { 42 | use proto::common::ResourceCode as ResourceType; 43 | 44 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 45 | let to: Address = matches.value_of("RECIPIENT")?.parse().ok()?; 46 | 47 | let resource_type = match matches.value_of("type") { 48 | Some("bandwidth") => ResourceType::Bandwidth, 49 | Some("energy") => ResourceType::Energy, 50 | _ => unreachable!("checks values in clap; qed"), 51 | }; 52 | 53 | let inner = contract_pb::UnfreezeBalanceContract { 54 | owner_address: from.as_bytes().into(), 55 | resource: resource_type as i32, 56 | receiver_address: if from == to { vec![] } else { to.as_bytes().into() }, 57 | }; 58 | 59 | Some(inner.into()) 60 | } 61 | 62 | fn vote(matches: &ArgMatches) -> Option { 63 | use proto::common::Vote; 64 | 65 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 66 | let votes = match matches.values_of("VOTES") { 67 | Some(vote_args) => vote_args 68 | .chunks(2) 69 | .into_iter() 70 | .map(|chunk| { 71 | if let &[addr, count] = &chunk.collect::>()[..] { 72 | Ok(Vote { 73 | vote_address: addr.parse::
()?.as_bytes().to_owned(), 74 | vote_count: crate::util::parse_amount(count).expect("parse amount failed"), 75 | }) 76 | } else { 77 | unreachable!("restricted by cli.yml; qed") 78 | } 79 | }) 80 | .collect::, Box>>() 81 | .ok()?, 82 | _ => vec![], 83 | }; 84 | 85 | let inner = contract_pb::VoteWitnessContract { 86 | owner_address: from.as_bytes().into(), 87 | votes: votes, 88 | ..Default::default() 89 | }; 90 | 91 | Some(inner.into()) 92 | } 93 | 94 | fn withdraw(matches: &ArgMatches) -> Option { 95 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 96 | 97 | let inner = contract_pb::WithdrawBalanceContract { 98 | owner_address: from.as_bytes().into(), 99 | }; 100 | 101 | Some(inner.into()) 102 | } 103 | -------------------------------------------------------------------------------- /ztron/src/precompiles/helper.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | use types::{H160, H256, U256}; 3 | 4 | use super::Error; 5 | 6 | const WORD_SIZE: usize = 32; 7 | 8 | pub struct AbiArgIterator<'a> { 9 | data: &'a [u8], 10 | offset: usize, 11 | } 12 | 13 | impl<'a> AbiArgIterator<'a> { 14 | pub fn new<'b>(data: &'b [u8]) -> AbiArgIterator<'b> { 15 | AbiArgIterator { data, offset: 0 } 16 | } 17 | 18 | pub fn is_ended(&self) -> bool { 19 | self.offset == self.data.len() 20 | } 21 | 22 | pub fn next_byte32(&mut self) -> Result<&'a [u8], Error> { 23 | if self.offset < self.data.len() { 24 | let ret = &self.data[self.offset..self.offset + WORD_SIZE]; 25 | self.offset += WORD_SIZE; 26 | Ok(ret) 27 | } else { 28 | Err(Error::AbiDecode) 29 | } 30 | } 31 | 32 | pub fn next_byte32_as_array(&mut self) -> Result<[u8; 32], Error> { 33 | let mut ret = [0u8; WORD_SIZE]; 34 | ret.copy_from_slice(self.next_byte32()?); 35 | Ok(ret) 36 | } 37 | 38 | pub fn next_fixed_words(&mut self, n: usize) -> Result<&'a [u8], Error> { 39 | if self.offset < self.data.len() { 40 | let ret = &self.data[self.offset..self.offset + n * WORD_SIZE]; 41 | self.offset += n * WORD_SIZE; 42 | Ok(ret) 43 | } else { 44 | Err(Error::AbiDecode) 45 | } 46 | } 47 | 48 | pub fn next_u256(&mut self) -> Result { 49 | self.next_byte32().map(U256::from_big_endian) 50 | } 51 | 52 | pub fn next_h256(&mut self) -> Result { 53 | self.next_byte32().map(H256::from_slice) 54 | } 55 | 56 | pub fn next_h160(&mut self) -> Result { 57 | self.next_h256().map(From::from) 58 | } 59 | 60 | pub fn next_bytes(&mut self) -> Result<&'a [u8], Error> { 61 | let local_offset: usize = self.next_u256()?.try_into().map_err(|_| Error::AbiDecode)?; 62 | 63 | let size: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 64 | .try_into() 65 | .map_err(|_| Error::AbiDecode)?; 66 | Ok(&self.data[local_offset + WORD_SIZE..local_offset + WORD_SIZE + size]) 67 | } 68 | 69 | pub fn next_array_of_bytes(&mut self) -> Result, Error> { 70 | // memory offset 71 | let mut local_offset: usize = self.next_u256()?.try_into().map_err(|_| Error::AbiDecode)?; 72 | 73 | if local_offset < self.data.len() { 74 | let len: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 75 | .try_into() 76 | .map_err(|_| Error::AbiDecode)?; 77 | local_offset += WORD_SIZE; 78 | 79 | let mut inner = AbiArgIterator::new(&self.data[local_offset..]); 80 | (0..len).map(|_| inner.next_bytes()).collect() 81 | } else { 82 | Ok(vec![]) 83 | } 84 | } 85 | 86 | pub fn next_array_of_byte32(&mut self) -> Result, Error> { 87 | self.next_array_of_fixed_words(1) 88 | } 89 | 90 | pub fn next_array_of_fixed_words(&mut self, n: usize) -> Result, Error> { 91 | // memory offset 92 | let mut local_offset: usize = self.next_u256()?.try_into().map_err(|_| Error::AbiDecode)?; 93 | 94 | if local_offset < self.data.len() { 95 | let len: usize = U256::from_big_endian(&self.data[local_offset..local_offset + WORD_SIZE]) 96 | .try_into() 97 | .map_err(|_| Error::AbiDecode)?; 98 | local_offset += WORD_SIZE; 99 | 100 | let mut inner = AbiArgIterator::new(&self.data[local_offset..]); 101 | (0..len).map(|_| inner.next_fixed_words(n)).collect() 102 | } else { 103 | Ok(vec![]) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /merkle-tree/src/merkle_tree.rs: -------------------------------------------------------------------------------- 1 | use crate::tree::{LeavesIntoIterator, LeavesIterator, Tree}; 2 | use crate::MerkleHasher; 3 | use types::H256; 4 | 5 | /// A Merkle tree is a binary tree, with values of type `T` at the leafs, 6 | /// and where every internal node holds the hash of the concatenation of the hashes of its children nodes. 7 | #[derive(Clone, Debug)] 8 | pub struct MerkleTree { 9 | /// The root of the inner binary tree 10 | root: Tree, 11 | 12 | /// The height of the tree 13 | height: usize, 14 | 15 | /// The number of leaf nodes in the tree 16 | count: usize, 17 | } 18 | 19 | impl MerkleTree { 20 | /// Constructs a Merkle Tree from a vector of data blocks. 21 | /// Returns `None` if `values` is empty. 22 | pub fn from_vec(values: Vec) -> Self { 23 | if values.is_empty() { 24 | return MerkleTree { 25 | root: Tree::empty(H::hash_empty()), 26 | height: 0, 27 | count: 0, 28 | }; 29 | } 30 | 31 | let count = values.len(); 32 | let mut height = 0; 33 | let mut cur = Vec::with_capacity(count); 34 | 35 | for v in values { 36 | let hash = H::hash(&v); 37 | let leaf = Tree::new(hash, v); 38 | cur.push(leaf); 39 | } 40 | 41 | while cur.len() > 1 { 42 | let mut next = Vec::new(); 43 | while !cur.is_empty() { 44 | if cur.len() == 1 { 45 | next.push(cur.remove(0)); 46 | } else { 47 | let left = cur.remove(0); 48 | let right = cur.remove(0); 49 | 50 | let combined_hash = H::hash_nodes(left.hash(), right.hash()); 51 | 52 | let node = Tree::Node { 53 | hash: combined_hash, 54 | left: Box::new(left), 55 | right: Box::new(right), 56 | }; 57 | 58 | next.push(node); 59 | } 60 | } 61 | 62 | height += 1; 63 | 64 | cur = next; 65 | } 66 | 67 | debug_assert!(cur.len() == 1); 68 | 69 | let root = cur.remove(0); 70 | 71 | MerkleTree { 72 | root: root, 73 | height: height, 74 | count: count, 75 | } 76 | } 77 | 78 | /// Returns the root hash of Merkle tree 79 | pub fn root_hash(&self) -> &H256 { 80 | self.root.hash() 81 | } 82 | 83 | /// Returns the height of Merkle tree 84 | pub fn height(&self) -> usize { 85 | self.height 86 | } 87 | 88 | /// Returns the number of leaves in the Merkle tree 89 | pub fn count(&self) -> usize { 90 | self.count 91 | } 92 | 93 | /// Returns whether the Merkle tree is empty or not 94 | pub fn is_empty(&self) -> bool { 95 | self.count() == 0 96 | } 97 | 98 | /// Creates an `Iterator` over the values contained in this Merkle tree. 99 | pub fn iter(&self) -> LeavesIterator { 100 | self.root.iter() 101 | } 102 | } 103 | 104 | impl IntoIterator for MerkleTree { 105 | type Item = H::Input; 106 | type IntoIter = LeavesIntoIterator; 107 | 108 | /// Creates a consuming iterator, that is, one that moves each value out of the Merkle tree. 109 | /// The tree cannot be used after calling this. 110 | fn into_iter(self) -> Self::IntoIter { 111 | self.root.into_iter() 112 | } 113 | } 114 | 115 | impl<'a, H: MerkleHasher> IntoIterator for &'a MerkleTree { 116 | type Item = &'a H::Input; 117 | type IntoIter = LeavesIterator<'a, H::Input>; 118 | 119 | /// Creates a borrowing `Iterator` over the values contained in this Merkle tree. 120 | fn into_iter(self) -> Self::IntoIter { 121 | self.root.iter() 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /ztron/tests/transfer.hex: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006e01ca183ffa92ca866e2686083b4eb89dc298bc657993d0d0110920ba985b06454f1256dc308d5f637ded48d6ea62cbe92e235ac7d72aae4ac085c3f4352815a034b3fd5a101c9b40c39819673cd6b23961dbed2a8558a1be3e2590ac65846f2fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ebeb2d7178fd9d10eabe9224855f7c65affc9a83e7d50686f6b2372e84e4681d3b76250737bafee7a27e7b36613ac1f77dcbe806839493e95921c0f2237727358787489a62f41dfddd57752fb9327b8a491e9739016dbad17a2c95d3e41cd460d5e242fced1a9fe763bd99144e34446ebfd72eb2c0e28a909aec63409bf235b78c222821074043cae7daa71924c4e68d8a453924f347d1a94e1b8e437a3f24aecb05ee9f123422302b45182a9ed2492db23809a69baf83fc1d0fa4bb73be080d312a19a80abd0a09e09d0469782d218a1a2811bf691d0a5ea5e9f630e81c13fc0a8ad4d7886e5c3a5342e88260ccff37f457f2362f326be0b303a3ee2d69849482d15d48210f0fd365499293f3c0a8d5b300c37a0fd64285e6c7f816086e2618fd7b7ba8345c45c8394f1ca9969a6f58d5eaa48b2c0aab21b30184f8a529c0b6000000000000000000000000000000000000000000000000000000000000000103d673c8092d478da5efd24e278bdf8619025965228505c78088da96e46745de0f366bd26148da102a0854ab2a6709cdd731dd39a4877878537f1ca27e69420c0000000000000000000000000000000000000000000000000000000000000001e79c89d994b577ebb08ed6c97e900f43e72b25eff766e50dca40b58dc04219152b9c844ea70dd6a757dad985a714d71ac7ffc81eee9a28e9826c265bb05a62a6dafd3897213ede4f8d7fbd9fac1f2356a10db98658ecee09c199eb5de6db0e5e881f222fa928f61792fc1af7143424aef3d3051a382f9b953379f62f9406276a5a94efadf2a049a2220c67c04623888fa86be71fd6c0567bd38a03b32f3edc00440689196e96db17f849e239c77005edc30b0e3a3b536efe618aa7d8d83fdddc05afeed58b8b6ef983bc788aca0f71cfceba24bd34ce656f5c9ff709ed32a08d535ea1338ed8d26404a4fa3aff9522d7b4b2c3f0d910f9e07f022fb1d47d70cf3cc535eee8126c2dffc91ab324a4c724b135db164e3a157db59557d7802d1cce 2 | -------------------------------------------------------------------------------- /context/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | use std::error::Error; 3 | use std::path::Path; 4 | use std::sync::atomic::{AtomicBool, AtomicU32}; 5 | use std::sync::RwLock; 6 | 7 | use chain::{IndexedBlock, IndexedTransaction}; 8 | use chain_db::ChainDB; 9 | use config::genesis::GenesisConfig; 10 | use config::Config; 11 | use log::info; 12 | use manager::Manager; 13 | use proto::common::BlockId; 14 | use tokio::sync::broadcast; 15 | use types::H256; 16 | 17 | pub struct AppContext { 18 | pub outbound_ip: String, 19 | pub node_id: Vec, 20 | pub genesis_block_id: Option, 21 | pub config: Config, 22 | pub genesis_config: GenesisConfig, 23 | pub num_active_connections: AtomicU32, 24 | pub num_passive_connections: AtomicU32, 25 | pub running: AtomicBool, 26 | pub syncing: AtomicBool, 27 | pub chain_db: ChainDB, 28 | /// state-db manager 29 | pub manager: RwLock, 30 | pub recent_block_ids: RwLock>, 31 | /// The termination signal is used to close all connections and services. 32 | pub termination_signal: broadcast::Sender<()>, 33 | // broadcasting channels across node 34 | /// outgoing transactions 35 | pub advertising_transaction_tx: broadcast::Sender, 36 | /// generated blocks 37 | pub advertising_block_tx: broadcast::Sender, 38 | /// transactions from api and channel protocol 39 | pub incoming_transaction_tx: broadcast::Sender, 40 | /// blocks from channel protocol 41 | pub incoming_block_tx: broadcast::Sender, 42 | } 43 | 44 | impl AppContext { 45 | pub fn from_config>(path: P) -> Result> { 46 | let config = Config::load_from_file(&path)?; 47 | 48 | let genesis_path = path.as_ref().parent().unwrap().join(&config.chain.genesis); 49 | 50 | let genesis_config = GenesisConfig::load_from_file(&genesis_path)?; 51 | let genesis_blk = genesis_config.to_indexed_block()?; 52 | 53 | let chain_db = ChainDB::new(&config.storage.data_dir); 54 | if !chain_db.has_block(&genesis_blk) { 55 | if let Ok(_) = chain_db.get_genesis_block() { 56 | panic!("genesis block config is inconsistent with chain-db"); 57 | } 58 | chain_db.insert_block(&genesis_blk)?; 59 | info!("inserted genesis block to chain-db"); 60 | } 61 | chain_db.report_status(); 62 | 63 | let genesis_block_id = BlockId { 64 | number: 0, 65 | hash: genesis_blk.header.hash.as_ref().to_owned(), 66 | }; 67 | 68 | let node_id = chain_db.get_node_id(); 69 | info!("node id => {}", hex::encode(&node_id)); 70 | info!("p2p version => {}", config.chain.p2p_version); 71 | info!("genesis block id => {}", hex::encode(&genesis_block_id.hash)); 72 | info!("chain-db loaded"); 73 | 74 | let mut db_manager = Manager::new(&config, &genesis_config); 75 | let ref_block_hashes = chain_db.ref_block_hashes_of_block_num(db_manager.latest_block_number()); 76 | db_manager.init_ref_blocks(ref_block_hashes); 77 | 78 | Ok(AppContext { 79 | chain_db, 80 | config, 81 | genesis_config, 82 | node_id, 83 | outbound_ip: "127.0.0.1".to_string(), 84 | genesis_block_id: Some(genesis_block_id), 85 | running: AtomicBool::new(true), 86 | syncing: AtomicBool::new(false), 87 | num_active_connections: AtomicU32::new(0), 88 | num_passive_connections: AtomicU32::new(0), 89 | recent_block_ids: RwLock::new(HashSet::new()), 90 | manager: RwLock::new(db_manager), 91 | termination_signal: broadcast::channel(1024).0, 92 | advertising_transaction_tx: broadcast::channel(1000).0, 93 | advertising_block_tx: broadcast::channel(10).0, 94 | incoming_transaction_tx: broadcast::channel(1000).0, 95 | incoming_block_tx: broadcast::channel(10).0, 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /config/src/genesis.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fs; 3 | use std::path::Path; 4 | 5 | use chain::IndexedBlock; 6 | use keys::Address; 7 | use proto::chain::{block_header::Raw as BlockHeaderRaw, transaction::Raw as TransactionRaw, BlockHeader, Transaction}; 8 | use proto::contract::TransferContract; 9 | use serde::{Deserialize, Serialize}; 10 | 11 | #[derive(Serialize, Deserialize, Debug, Clone)] 12 | pub struct Witness { 13 | pub address: String, 14 | pub url: String, 15 | pub votes: i64, 16 | } 17 | 18 | #[derive(Serialize, Deserialize, Debug, Clone)] 19 | pub struct Alloc { 20 | pub address: String, 21 | pub name: String, 22 | pub balance: i64, 23 | } 24 | 25 | impl Alloc { 26 | fn to_transaction(&self, sender: &[u8]) -> Result> { 27 | let transfer_contract = TransferContract { 28 | owner_address: sender.to_owned(), 29 | to_address: self.address.parse::
()?.as_bytes().to_owned(), 30 | amount: self.balance, 31 | }; 32 | let raw = TransactionRaw { 33 | contract: Some(transfer_contract.into()), 34 | ..Default::default() 35 | }; 36 | let transaction = Transaction { 37 | raw_data: Some(raw).into(), 38 | ..Default::default() 39 | }; 40 | Ok(transaction) 41 | } 42 | } 43 | 44 | #[derive(Serialize, Deserialize, Debug, Clone)] 45 | pub struct GenesisConfig { 46 | pub timestamp: i64, 47 | #[serde(rename = "parentHash")] 48 | parent_hash: String, 49 | mantra: String, 50 | creator: String, 51 | pub witnesses: Vec, 52 | pub allocs: Vec, 53 | } 54 | 55 | impl GenesisConfig { 56 | pub fn load_from_file>(path: P) -> Result> { 57 | let content = fs::read_to_string(path)?; 58 | Ok(serde_json::from_str(&content)?) 59 | } 60 | 61 | pub fn load_from_str(content: &str) -> Result> { 62 | Ok(serde_json::from_str(&content)?) 63 | } 64 | 65 | fn to_block_header(&self) -> BlockHeader { 66 | let raw_header = BlockHeaderRaw { 67 | number: 0, 68 | timestamp: self.timestamp, 69 | witness_address: self.mantra.as_bytes().to_owned(), 70 | parent_hash: parse_hex(&self.parent_hash), 71 | // merkle_root_hash will be filled by indexed block header 72 | ..Default::default() 73 | }; 74 | BlockHeader { 75 | raw_data: Some(raw_header).into(), 76 | ..Default::default() 77 | } 78 | } 79 | 80 | pub fn to_indexed_block(&self) -> Result> { 81 | let sender = keys::b58decode_check(&self.creator)?; 82 | let transactions = self 83 | .allocs 84 | .iter() 85 | .map(|alloc| alloc.to_transaction(&sender)) 86 | .collect::, Box>>()?; 87 | 88 | Ok(IndexedBlock::from_raw_header_and_txns(self.to_block_header(), transactions).unwrap()) 89 | } 90 | } 91 | 92 | fn parse_hex(encoded: &str) -> Vec { 93 | if encoded.starts_with("0x") { 94 | hex::decode(&encoded[2..]).unwrap() 95 | } else { 96 | hex::decode(encoded).unwrap() 97 | } 98 | } 99 | 100 | #[cfg(test)] 101 | mod tests { 102 | use super::*; 103 | 104 | #[test] 105 | fn load_genesis_json() { 106 | let content = include_str!("../../etc/genesis.json"); 107 | let conf: GenesisConfig = serde_json::from_str(&content).unwrap(); 108 | 109 | let block = conf.to_indexed_block().unwrap(); 110 | println!("block => {:?}", block); 111 | // mainnet: "8ef446bf3f395af929c218014f6101ec86576c5f61b2ae3236bf3a2ab5e2fecd" 112 | // nile: "6556a96828248d6b89cfd0487d4cef82b134b5544dc428c8a218beb2db85ab24" 113 | // shasta: "ea97ca7ac977cf2765093fa0e4732e561dc4ff8871c17e35fd2bcabb8b5f821d" 114 | 115 | println!("block_id => {:?}", hex::encode(block.merkle_root_hash())); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /state/src/parameter.rs: -------------------------------------------------------------------------------- 1 | //! Chain parameters, can be modified by proposals. 2 | 3 | use config::ChainParameterConfig; 4 | 5 | #[doc(inline)] 6 | pub use proto::state::ChainParameter; 7 | 8 | pub fn default_parameters() -> impl IntoIterator { 9 | use ChainParameter::*; 10 | 11 | return vec![ 12 | (MaintenanceInterval, 21600_000), 13 | (MaxCpuTimeOfOneTxn, 50), 14 | (RemovePowerOfGr, 0), 15 | (AllowUpdateAccountName, 0), 16 | (AllowSameTokenName, 0), 17 | (AllowDelegateResource, 0), 18 | (AllowMultisig, 0), 19 | (AllowAccountStateRoot, 0), 20 | (AllowChangeDelegation, 0), 21 | (AllowTvm, 0), 22 | (ForbidTransferToContract, 0), 23 | (BandwidthPrice, 10), 24 | (EnergyPrice, 100), 25 | (WitnessCreateFee, 9999_000_000), 26 | (AccountCreateFee, 100_000), 27 | (AccountPermissionUpdateFee, 100_000_000), 28 | (AssetIssueFee, 1024_000_000), 29 | (ExchangeCreateFee, 1024_000_000), 30 | (MultisigFee, 1_000_000), 31 | (CreateNewAccountFeeInSystemContract, 0), 32 | (CreateNewAccountBandwidthRate, 1), 33 | (TotalEnergyLimit, 50_000_000_000), 34 | // = TotalEnergyLimit 35 | // (TotalEnergyCurrentLimit, 50_000_000_000), 36 | (AllowAdaptiveEnergy, 0), 37 | (AdaptiveResourceLimitTargetRatio, 14400), 38 | (AdaptiveResourceLimitMultiplier, 1_000), 39 | // Only used before AllowChangeDelegation 40 | (StandbyWitnessAllowance, 115_200_000_000), 41 | (WitnessPayPerBlock, 32_000_000), 42 | (StandbyWitnessPayPerBlock, 16_000_000), 43 | (AllowTvmTransferTrc10Upgrade, 0), 44 | (AllowTvmConstantinopleUpgrade, 0), 45 | (AllowTvmSolidity059Upgrade, 0), 46 | (AllowTvmShieldedUpgrade, 0), 47 | (AllowTvmIstanbulUpgrade, 0), 48 | (AllowProtoFilterNum, 0), 49 | ]; 50 | } 51 | 52 | pub fn default_parameters_from_config( 53 | config: &ChainParameterConfig, 54 | ) -> impl IntoIterator { 55 | use ChainParameter::*; 56 | 57 | return vec![ 58 | (MaintenanceInterval, config.maintenance_interval), 59 | (MaxCpuTimeOfOneTxn, 50), 60 | (RemovePowerOfGr, 0), 61 | (AllowUpdateAccountName, 0), 62 | (AllowSameTokenName, config.allow_duplicate_asset_names as i64), 63 | (AllowDelegateResource, config.allow_delegate_resource as i64), 64 | (AllowMultisig, config.allow_multisig as i64), 65 | (AllowAccountStateRoot, 0), 66 | (AllowChangeDelegation, 0), 67 | (AllowTvm, config.allow_tvm as i64), 68 | (ForbidTransferToContract, 0), 69 | (BandwidthPrice, config.bandwidth_price), 70 | (EnergyPrice, config.energy_price), 71 | (WitnessCreateFee, 9999_000_000), 72 | (AccountCreateFee, 100_000), 73 | (AccountPermissionUpdateFee, 100_000_000), 74 | (AssetIssueFee, 1024_000_000), 75 | (ExchangeCreateFee, 1024_000_000), 76 | (MultisigFee, 1_000_000), 77 | (CreateNewAccountFeeInSystemContract, 0), 78 | (CreateNewAccountBandwidthRate, 1), 79 | (TotalEnergyLimit, 50_000_000_000), 80 | // Same as TotalEnergyLimit, 81 | (TotalEnergyCurrentLimit, 50_000_000_000), 82 | (AllowAdaptiveEnergy, config.allow_adaptive_energy as i64), 83 | (AdaptiveResourceLimitTargetRatio, 14400), 84 | (AdaptiveResourceLimitMultiplier, 1_000), 85 | (WitnessPayPerBlock, 32_000_000), 86 | (StandbyWitnessAllowance, 115_200_000_000), 87 | (StandbyWitnessPayPerBlock, 16_000_000), 88 | ( 89 | AllowTvmTransferTrc10Upgrade, 90 | config.allow_tvm_transfer_trc10_upgrade as i64, 91 | ), 92 | ( 93 | AllowTvmConstantinopleUpgrade, 94 | config.allow_tvm_constantinople_upgrade as i64, 95 | ), 96 | (AllowTvmSolidity059Upgrade, config.allow_tvm_solidity_059_upgrade as i64), 97 | (AllowTvmShieldedUpgrade, config.allow_tvm_shielded_upgrade as i64), 98 | (AllowTvmIstanbulUpgrade, config.allow_tvm_istanbul_upgrade as i64), 99 | (AllowProtoFilterNum, 0), 100 | ]; 101 | } 102 | -------------------------------------------------------------------------------- /services/graphql/src/scalar.rs: -------------------------------------------------------------------------------- 1 | use async_graphql::{InputValueError, InputValueResult, Scalar, ScalarType, Value}; 2 | use types::H256; 3 | 4 | /// Bytes32 is a 32 byte binary string, represented as 0x-prefixed hexadecimal. 5 | #[derive(Clone, Copy, Debug, PartialEq)] 6 | pub struct Bytes32(pub H256); 7 | 8 | impl From for Bytes32 { 9 | fn from(value: H256) -> Self { 10 | Bytes32(value) 11 | } 12 | } 13 | 14 | #[Scalar] 15 | impl ScalarType for Bytes32 { 16 | fn parse(value: Value) -> InputValueResult { 17 | match value { 18 | Value::String(value) => { 19 | if value.starts_with("0x") { 20 | Ok(Bytes32(H256::from_slice(&hex::decode(&value[2..])?))) 21 | } else { 22 | Ok(Bytes32(H256::from_slice(&hex::decode(value)?))) 23 | } 24 | } 25 | Value::Number(value) => value 26 | .as_u64() 27 | .map(H256::from_low_u64_be) 28 | .map(Bytes32) 29 | .ok_or(InputValueError::custom("invalid number type")), 30 | _ => Err(InputValueError::expected_type(value)), 31 | } 32 | } 33 | 34 | fn to_value(&self) -> Value { 35 | Value::String(hex::encode(&self.0)) 36 | } 37 | } 38 | 39 | /// Address is a 20 byte Ethereum address, represented as 0x-prefixed hexadecimal. 40 | #[derive(Clone, Copy, Debug, PartialEq)] 41 | pub struct Address(pub keys::Address); 42 | 43 | impl From for Address { 44 | fn from(value: keys::Address) -> Address { 45 | Address(value) 46 | } 47 | } 48 | 49 | impl Default for Address { 50 | fn default() -> Address { 51 | Address(keys::Address::default()) 52 | } 53 | } 54 | 55 | #[Scalar] 56 | impl ScalarType for Address { 57 | fn parse(value: Value) -> InputValueResult { 58 | match value { 59 | Value::String(value) => Ok(value.parse().map(Address)?), 60 | _ => Err(InputValueError::expected_type(value)), 61 | } 62 | } 63 | 64 | fn to_value(&self) -> Value { 65 | Value::String(self.0.to_string()) 66 | } 67 | } 68 | 69 | /// Bytes is an arbitrary length binary string, represented as 0x-prefixed hexadecimal. 70 | /// An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles. 71 | pub struct Bytes(pub Vec); 72 | 73 | #[Scalar] 74 | impl ScalarType for Bytes { 75 | fn parse(value: Value) -> InputValueResult { 76 | match value { 77 | Value::String(value) => { 78 | if value.starts_with("0x") { 79 | Ok(hex::decode(&value[2..]).map(Bytes)?) 80 | } else { 81 | Ok(hex::decode(value).map(Bytes)?) 82 | } 83 | } 84 | _ => Err(InputValueError::expected_type(value)), 85 | } 86 | } 87 | 88 | fn to_value(&self) -> Value { 89 | Value::String(hex::encode(&self.0)) 90 | } 91 | } 92 | 93 | impl From for Vec { 94 | fn from(value: Bytes) -> Vec { 95 | value.0 96 | } 97 | } 98 | 99 | // /// BigInt is a large integer. Input is accepted as either a JSON number or as a string. 100 | // /// Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all 101 | // /// 0x-prefixed hexadecimal. 102 | // pub struct BigInt(BigInt); 103 | 104 | /// Long is a 64 bit unsigned integer. 105 | #[derive(Clone, Copy, Debug, PartialEq)] 106 | pub struct Long(pub i64); 107 | 108 | impl From for Long { 109 | fn from(value: i64) -> Self { 110 | Long(value) 111 | } 112 | } 113 | 114 | #[Scalar] 115 | impl ScalarType for Long { 116 | fn parse(value: Value) -> InputValueResult { 117 | match value { 118 | Value::String(value) => Ok(value.parse().map(Long)?), 119 | Value::Number(value) => value 120 | .as_i64() 121 | .map(Long) 122 | .ok_or(InputValueError::custom("invalid number type")), 123 | _ => Err(InputValueError::expected_type(value)), 124 | } 125 | } 126 | 127 | fn to_value(&self) -> Value { 128 | Value::String(self.0.to_string()) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /constants/src/block_version.rs: -------------------------------------------------------------------------------- 1 | //! Block version releated constants. 2 | 3 | /// ForkPolicies for different versions. 4 | #[derive(Debug, PartialEq, Eq)] 5 | pub enum ForkPolicy { 6 | // only used in then ENERGY_LIMIT fork 7 | AtBlock { block_number: i64 }, 8 | // passOld 9 | Old, 10 | // passNew(>4.0.0) 11 | New { timestamp: i64, min_upgrade_percent: u8 }, 12 | } 13 | 14 | /// Block versions. These versions match version names on github release page(or PR numbers). 15 | #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] 16 | pub enum BlockVersion { 17 | /// Also applies to all blocks before around #2300000. 18 | Genesis = 0, 19 | Unknown1290 = 1, 20 | // PR #1442 21 | Odyssey3_0_1 = 2, 22 | // PR #1485 23 | Odyssey3_1_0 = 3, 24 | /// Special Check after block #4727890 (enery.limit.block.num). 25 | /// When block.version == 5, 26 | /// it makes block use new energy to handle transaction when block number >= 4727890L. 27 | /// Otherwise version !=5, skip. 28 | /// 29 | /// - Support Of Resource Delegation. 30 | /// - UpdateEnergyLimitContract 31 | /// - TotalEnergyLimit 32 | /// - AllowTvmTransferTrc10Upgrade 33 | /// - CALLTOKEN, TOKENBALANCE, CALLTOKENVALUE, CALLTOKENID 34 | /// 35 | /// Renamed: ENERGY_LIMIT 36 | Odyssey3_2 = 5, 37 | /// - Deprecates `TotalEnergyLimit` 38 | /// - Add `TotalCurrentEnergyLimit` 39 | Odyssey3_2_2 = 6, 40 | /// - AllowMultisig 41 | /// - AllowAdaptiveEnergy 42 | /// - UpdateAccountPermissionFee 43 | /// - MultisigFee 44 | Odyssey3_5 = 7, 45 | /// - AllowProtoFilterNum 46 | /// - AllowAccountStateRoot 47 | /// - AllowTvmConstantinopleUpgrade 48 | /// - ClearABI 49 | /// - reject delegate resource to contract address 50 | /// - Save runtime code from deploy code 51 | /// - SHL, SHR, SAR, fake CREATE2, EXTCODEHASH 52 | /// - Introduce TransferException 53 | Odyssey3_6_0 = 8, 54 | /// - AllowTvmSolidity059Upgrade 55 | /// - create account while transfer TRX/TRC10 56 | /// - batchvalidatesig, validatemultisig 57 | /// - ISCONTRACT 58 | /// - AdaptiveResourceLimitTargetRatio 59 | /// - AdaptiveResourceLimitMultiplier 60 | /// - AllowChangeDelegation 61 | /// - StandbyWitnessPayPerBlock 62 | Odyssey3_6_5 = 9, 63 | /// - ForbidTransferToContract 64 | Odyssey3_6_6 = 10, 65 | // NOTE: This version has only non-core API changes. Should not be a version fork. 66 | /// On Nile testnet, this is the `AllowShieldedTransaction` fork. 67 | /// 68 | /// See-also: https://github.com/tronprotocol/java-tron/pull/3372 69 | /// 70 | /// See-also: block 1628391 of Nile testnet 71 | Odyssey3_7 = 15, 72 | /// Shielded TVM precompiles. 73 | /// 74 | /// - support AllowTvmShieldedUpgrade config 75 | GreatVoyage4_0_0 = 16, 76 | /// First hard fork based on timestamp. Fork at 1596780000_000, at least 22 SRs. 77 | /// 78 | /// See-also: https://github.com/tronprotocol/java-tron/pull/3314 79 | /// 80 | /// - support AllowTvmShieldedUpgrade proposal 81 | GreatVoyage4_0_1 = 17, 82 | /// - AllowPbft 83 | /// - AllowTvmIstanbulUpgrade 84 | /// - AllowMarketTransaction 85 | /// - MarketSellFee 86 | /// - MarketCancelFee 87 | GreatVoyage4_1_0 = 19, 88 | /// - MaxFeeLimit 89 | /// - AllowTransactionFeePool 90 | /// - AllowBlackholeOptimization 91 | GreatVoyage4_1_2 = 20, 92 | } 93 | 94 | impl BlockVersion { 95 | pub fn fork_policy(&self) -> ForkPolicy { 96 | match *self { 97 | BlockVersion::GreatVoyage4_1_0 | BlockVersion::GreatVoyage4_0_1 | BlockVersion::GreatVoyage4_1_2 => { 98 | ForkPolicy::New { 99 | // GMT 2020-08-07 06:00:00 100 | timestamp: 1596780000_000, 101 | // 27 * 0.8 = 21.6 102 | min_upgrade_percent: 80, 103 | } 104 | } 105 | BlockVersion::Odyssey3_2 => ForkPolicy::AtBlock { block_number: 4727890 }, 106 | _ => ForkPolicy::Old, 107 | } 108 | } 109 | 110 | /// The ENERGY_LIMIT fork at block #4727890. 111 | #[allow(non_snake_case)] 112 | pub const fn ENERGY_LIMIT() -> BlockVersion { 113 | BlockVersion::Odyssey3_2 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tvm/src/precompile/tron.rs: -------------------------------------------------------------------------------- 1 | use libsecp256k1::{Message, RecoveryId, Signature}; 2 | use sha3::{Digest, Keccak256}; 3 | use std::convert::TryInto; 4 | use types::{H160, H256, U256}; 5 | 6 | use super::helper::AbiArgIterator; 7 | use crate::backend::Backend; 8 | 9 | pub fn ecrecover(input: &[u8]) -> Option { 10 | let v: u8 = U256::from_big_endian(&input[32..64]).try_into().ok()?; 11 | 12 | let msg = Message::parse_slice(&input[0..32]).ok()?; 13 | let sig = Signature::parse_overflowing_slice(&input[64..128]).ok()?; 14 | // TRON: rec_id fix is same as EVM 15 | let rec_id = RecoveryId::parse(v.wrapping_sub(27)).ok()?; 16 | 17 | let pub_key = libsecp256k1::recover(&msg, &sig, &rec_id).ok()?; 18 | let raw_pub_key = pub_key.serialize(); 19 | 20 | let mut hasher = Keccak256::new(); 21 | hasher.update(&raw_pub_key[1..]); // skip [0], type byte 22 | let digest = hasher.finalize(); 23 | 24 | let mut ret = H256::zero(); 25 | ret.as_bytes_mut()[12..32].copy_from_slice(&digest[digest.len() - 20..]); 26 | Some(ret) 27 | } 28 | 29 | // [u8; 32], [u8; 65] => [u8; 20] 30 | fn recover_addr(message: &[u8], signature: &[u8]) -> Option { 31 | let msg = Message::parse_slice(message).ok()?; 32 | let sig = Signature::parse_overflowing_slice(&signature[..64]).ok()?; 33 | // NOTE: no wrapping_sub 34 | let rec_id = RecoveryId::parse(signature[64]).ok()?; 35 | 36 | let pub_key = libsecp256k1::recover(&msg, &sig, &rec_id).ok()?; 37 | let raw_pub_key = pub_key.serialize(); 38 | 39 | let mut hasher = Keccak256::new(); 40 | hasher.update(&raw_pub_key[1..]); // skip [0], type byte 41 | let digest = hasher.finalize(); 42 | 43 | let mut ret = H256::zero(); 44 | ret.as_bytes_mut()[12..32].copy_from_slice(&digest[digest.len() - 20..]); 45 | Some(ret.into()) 46 | } 47 | 48 | /// batchvalidatesign(bytes32 hash, bytes[] signatures, address[] addresses) returns (bytes32) 49 | pub fn batchvalidatesign(input: &[u8]) -> Option> { 50 | const MAX_NUM_OF_SIGNATURES: usize = 16; 51 | let mut it = AbiArgIterator::new(input); 52 | 53 | let hash = it.next_byte32()?; 54 | let sigs = it.next_array_of_bytes()?; 55 | let addrs = it.next_array_of_byte32()?; 56 | 57 | if sigs.len() != addrs.len() || sigs.is_empty() || sigs.len() > MAX_NUM_OF_SIGNATURES { 58 | return None; 59 | } 60 | 61 | let mut ret = vec![0u8; 32]; 62 | for i in 0..sigs.len() { 63 | if let Some(addr) = recover_addr(hash, sigs[i]) { 64 | if addr == H256::from_slice(addrs[i]).into() { 65 | ret[i] = 1; 66 | } 67 | } 68 | } 69 | 70 | Some(ret) 71 | } 72 | 73 | /// validatemultisign(address addr, uint256 permissionId, bytes32 hash, bytes[] signatures) returns (bool) 74 | pub fn validatemultisign(input: &[u8], backend: &dyn Backend) -> Option { 75 | let mut it = AbiArgIterator::new(input); 76 | 77 | let addr = it.next_h160()?; 78 | let perm_id = it.next_u256()?; 79 | let hash = it.next_h256()?; 80 | let sigs = it.next_array_of_bytes()?; 81 | 82 | Some(backend.validate_multisig(addr, perm_id, hash, &sigs)) 83 | } 84 | 85 | #[cfg(test)] 86 | mod tests { 87 | use super::*; 88 | 89 | #[test] 90 | fn test_batchvalidatesign() { 91 | let raw = hex::decode("a166ceae7066e25689f134a16f08d82911363e16d4911ca3a0c23159ff92aaf0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000413f0449db639f3993d075dca4b0c0adfcc214c4a55a268a3c4c0617e822ed38bb29ef0035547e28cee2c35bd79642cdbb66ecc5594e5089cd858f232a0f957663000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413f0449db639f3993d075dca4b0c0adfcc214c4a55a268a3c4c0617e822ed38bb29ef0035547e28cee2c35bd79642cdbb66ecc5594e5089cd858f232a0f9576630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000003d14645130f22f0b3b03f6966fdc3c7e3322f070000000000000000000000415cbdd86a2fa8dc4bddd8a8f69dba48572eec07fb").unwrap(); 92 | let ret = batchvalidatesign(&raw).unwrap(); 93 | assert_eq!(ret[0], 0); 94 | assert_eq!(ret[1], 1); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /manager/src/executor/actuators/transfer.rs: -------------------------------------------------------------------------------- 1 | /// TRX transfer. 2 | use std::convert::TryFrom; 3 | 4 | use ::keys::Address; 5 | use proto::chain::transaction::Result as TransactionResult; 6 | use proto::common::AccountType; 7 | use proto::contract as contract_pb; 8 | use proto::state::Account; 9 | use state::keys; 10 | 11 | use super::super::TransactionContext; 12 | use super::BuiltinContractExecutorExt; 13 | use crate::Manager; 14 | 15 | const TRANSFER_FEE: i64 = 0; 16 | 17 | impl BuiltinContractExecutorExt for contract_pb::TransferContract { 18 | fn validate(&self, manager: &Manager, ctx: &mut TransactionContext) -> Result<(), String> { 19 | let state_db = &manager.state_db; 20 | 21 | let owner_address = Address::try_from(&self.owner_address).map_err(|_| "invalid owner_address")?; 22 | let to_address = Address::try_from(&self.to_address).map_err(|_| "invalid to_address")?; 23 | 24 | let mut fee = self.fee(manager); 25 | 26 | if owner_address == to_address { 27 | return Err("cannot transfer to oneself".into()); 28 | } 29 | 30 | if self.amount <= 0 { 31 | return Err("transfer amount must be greater than 0".into()); 32 | } 33 | 34 | let owner_acct = state_db 35 | .get(&keys::Account(owner_address)) 36 | .map_err(|_| "error while querying db")? 37 | .ok_or_else(|| "owner account is not on chain")?; 38 | 39 | if let Some(spend) = self.amount.checked_add(fee) { 40 | if owner_acct.balance < spend { 41 | return Err(format!( 42 | "insufficient balance, balance={}, required={}", 43 | owner_acct.balance, spend 44 | )); 45 | } 46 | } else { 47 | return Err("math overflow".into()); 48 | } 49 | 50 | let maybe_to_acct = state_db 51 | .get(&keys::Account(to_address)) 52 | .map_err(|_| "error while querying db")?; 53 | 54 | match maybe_to_acct { 55 | None => { 56 | ctx.new_account_created = true; 57 | // NOTE: CreateNewAccountFeeInSystemContract is 0, 58 | // account creation fee is handled by BandwidthProcessor. 59 | fee += state_db.must_get(&keys::ChainParameter::CreateNewAccountFeeInSystemContract); 60 | } 61 | Some(to_acct) 62 | if to_acct.r#type == AccountType::Contract as i32 && 63 | state_db.must_get(&keys::ChainParameter::ForbidTransferToContract) == 1 => 64 | { 65 | return Err("cannot transfer to a smart contract address".into()); 66 | } 67 | Some(to_acct) => { 68 | to_acct 69 | .balance 70 | .checked_add(self.amount) 71 | .ok_or_else(|| "math overflow")?; 72 | } 73 | } 74 | 75 | ctx.contract_fee = fee; 76 | 77 | Ok(()) 78 | } 79 | 80 | fn execute(&self, manager: &mut Manager, ctx: &mut TransactionContext) -> Result { 81 | let owner_address = Address::try_from(&self.owner_address).unwrap(); 82 | let to_address = Address::try_from(&self.to_address).unwrap(); 83 | 84 | let mut owner_acct = manager.state_db.must_get(&keys::Account(owner_address)); 85 | 86 | let fee = ctx.contract_fee; 87 | 88 | let mut to_acct = manager 89 | .state_db 90 | .get(&keys::Account(to_address)) 91 | .map_err(|e| format!("state-db error: {:?}", e))? 92 | .unwrap_or_else(|| Account::new(manager.latest_block_timestamp())); 93 | 94 | if fee != 0 { 95 | owner_acct.adjust_balance(-fee).unwrap(); 96 | manager.add_to_blackhole(fee).unwrap(); 97 | } 98 | 99 | owner_acct.adjust_balance(-self.amount).unwrap(); 100 | to_acct.adjust_balance(self.amount).unwrap(); 101 | 102 | manager 103 | .state_db 104 | .put_key(keys::Account(owner_address), owner_acct) 105 | .map_err(|e| e.to_string())?; 106 | manager 107 | .state_db 108 | .put_key(keys::Account(to_address), to_acct) 109 | .map_err(|e| e.to_string())?; 110 | 111 | Ok(TransactionResult::success()) 112 | } 113 | 114 | fn fee(&self, _: &Manager) -> i64 { 115 | TRANSFER_FEE 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ztron/tests/transfer.to2.hex: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006e096e5f4936e1f1dc9308a4e49c6beaabb175e404a824300fd223ec227a25218df860be7e331623c8d994cbfdff99147fdd6daef66e46285c5f2f176d8b402b70aafc1401952aabee4d0664391b23fed17626e55de7fb6ed11a6342c163022269c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ebeb2d7178fd9d10eabe9224855f7c65affc9a83e7d50686f6b2372e84e4681d3b76250737bafee7a27e7b36613ac1f77dcbe806839493e95921c0f22377273576f436bc45c94cfc0602a65ed6db43bcc0ac6d92513f7617fcf1433cb6aaeb1bd471fce413e2a0dd8f397d956d3a9969a5a92406d0f0e4df1cebb731ff511be2b3a9917f7d97c82399e1de89820d20594db5c4f2066b1aba93ab18c1717840705f751a745e56c6127f724696803c65a2949cf2295f1c2eaab183c41e43f63dde12de2babed45217ae5bda30dc64fa18d2d7cace74a67127a66b6027d9d8d1bee15e86e02a6e7a833985172fc1e2808354009edc88e57547732578abaf49c57ba0228c9d53cc23698a5542d4edb4959cdaaa330ffb2933a1201ca16e3dd7d09a272ee491efc8ea7c7e13bcdcb7fc25422de0d9bad50af944505ebb6730355f73a0000000000000000000000000000000000000000000000000000000000000001c8da6d051e62e07c405759c6c0106e0665f734aae6d889d23a02d61657b0c5673bce8f1b4bb37293dfff205dd730f197f2cdb3b52446621cfcc70fea31b5e10b00000000000000000000000000000000000000000000000000000000000000026761583bcc88fcc34c39f6998cedae4414d9fa810b32b9e030539dbca9c1eb459a0f66d28325aa8dbd48f54c3b9123c387b373d5041bb739a9114a1d74b4d9e0202a2b1f311d850fb903a5de9d0cad1d009154cf6f0b057ffc3c07cd55b367f1ac3e1903a262c6fb1fc434274ca7b9531584c9e551c50b15fd9e47f3232670ddf213344442d0a3689770328cc470b085a81c8ac9c311e6a41970c96896669fc5d0fa1927e0f3a964ed16bfdb4d279603a262a630124b5340b241996923929301102b95e44b62b991849be1329a9720acffee86417e865293c597fedeab2669ccef87a0792bb0cb4f49e1b3d59dba454783e0ddc84b58877dd938605751ac39e327422e5881f201e3b7f12f152bbaede81b0bc32f41b53547905f63ef861168ca2edc95228aaf78ec2baac9d2eff5eac7dc549730e7330bbcdd1d2a91bbf08e4863c691ab1349d5219ad1a18349cd239d63b114d115cac2e4556f01e338a0b31a0218129e9004ef1df9a243e4a73fad9acf5cbabbcc1250fa79cc3ed5fcd66e9384870fbd1762e4285b754ee2b57aa755e3f1f7c309c5df4025c55acc335583e8e732ebc22c0595c60fcb8856495cee3ba6939304ca1b6b67ad380a418728191a6d1a1a15b86c34aaf60645520487da5498caba9b5d20d30b69e9084df86334db10679c0e428845b2365c7f2453bce8bee379d47f16b7a4036004536d11a813ea525662d724e860cc219c809280565756af73c5d36dbdeacadca4a12bc7bffbdb630977ccc9097f9855bccf5dc12584d8fbbf6f10472660ad2c465d76d0ecdc49 2 | -------------------------------------------------------------------------------- /state/src/property.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use super::ChainParameter; 4 | 5 | /// Used for DB migrations. Corresponding key is `DynamicProperty::DbVersion`. 6 | const CURRENT_DB_VERSION: i64 = 1; 7 | 8 | /// Dynamic properties of a living chain. 9 | #[derive(Debug, PartialEq, Eq, Hash)] 10 | pub enum DynamicProperty { 11 | /// For migration. 12 | DbVersion, 13 | 14 | // * Global IDs 15 | /// 1000000 (start, never used) 16 | LatestTokenId, 17 | /// 0, starts from 1 18 | LatestProposalId, 19 | /// 0, starts from 1 20 | LatestExchangeId, 21 | 22 | // * Latest Block 23 | LatestBlockTimestamp, 24 | LatestBlockNumber, 25 | // LatestBlockHash, 26 | LatestSolidBlockNumber, 27 | 28 | IsMaintenance, 29 | NextMaintenanceTime, 30 | HasNewVotesInCurrentEpoch, 31 | /// Number of maintenance passed. 32 | CurrentEpoch, 33 | 34 | // StateFlag, is in maintenance? 35 | // TODO fill slots 36 | BlockFilledSlotsIndex, 37 | 38 | // * Bandwidth 39 | /// Renamed: TotalNetWeight 40 | TotalBandwidthWeight, 41 | /// Renamed: TotalNetLimit 42 | /// 43 | /// Default: 43_200_000_000 44 | TotalBandwidthLimit, 45 | 46 | // * Adaptive Energy 47 | /// Accumulator frozen energy. 48 | TotalEnergyWeight, 49 | /// Default: getTotalEnergyLimit() / 14400 50 | /// Calculated when active. so = 6250000 51 | TotalEnergyTargetLimit, 52 | /// Default: 0 53 | TotalEnergyAverageUsage, 54 | TotalEnergyAverageSlot, 55 | // ChainParameter::TotalEnergyCurrentLimit = getTotalEnergyLimit() 56 | // ChainParameter::TotalEnergyLimit = 90000000000 57 | 58 | // * Global Free Bandwidth ('public' is ambiguous) 59 | /// Renamed: PublicNetLimit = 14_400_000_000 60 | GlobalFreeBandwidthLimit, 61 | /// Renamed: PublicNetUsage = 0 62 | GlobalFreeBandwidthUsed, 63 | /// Renamed: PublicNetTime = 0 64 | GlobalFreeBandwidthLatestSlot, 65 | // * Unused and deprecated 66 | // ! Why a block scoped variable is saved to store? 67 | // BlockEnergyUsage 68 | 69 | // ! accumulator, unused 70 | // TotalTransactionCost 71 | // TotalCreateWitnessCost 72 | // TotalCreateWitnessCost 73 | // TotalCreateAccountCost 74 | 75 | // ! storage, unused 76 | // TotalStoragePool 77 | // TotalStorageTax 78 | // TotalStorageReserved 79 | // StorageExchangeTaxRate 80 | 81 | // ! should be a calculated/cached property 82 | // Default: 7fff1fc0037e0000000000000000000000000000000000000000000000000000 83 | // DefaultPermissionMask, 84 | // DefaultPermissionMask without UpdateAccountPermission 85 | // 86 | // Default: 7fff1fc0033e0000000000000000000000000000000000000000000000000000 87 | // ActivePermissionMask, 88 | 89 | // Unused in mainnet: TotalShieldedPoolValue 90 | } 91 | 92 | impl DynamicProperty { 93 | pub fn default_properties() -> impl IntoIterator { 94 | use self::DynamicProperty::*; 95 | 96 | return vec![ 97 | (DbVersion, CURRENT_DB_VERSION), 98 | (LatestTokenId, 1000000), 99 | (LatestProposalId, 0), 100 | (LatestExchangeId, 0), 101 | // LatestBlockTimestamp, 102 | // will be overwriten when apply genesis block 103 | (LatestBlockNumber, -1), 104 | (LatestSolidBlockNumber, -1), 105 | // * maintenance 106 | (IsMaintenance, 0), 107 | // FIXME: should be after genesis timestamp 108 | (NextMaintenanceTime, 0), 109 | (HasNewVotesInCurrentEpoch, 0), 110 | (CurrentEpoch, 0), 111 | (BlockFilledSlotsIndex, 0), 112 | // * bandwidth 113 | (TotalBandwidthWeight, 0), 114 | (TotalBandwidthLimit, 43_200_000_000), 115 | (TotalEnergyWeight, 0), 116 | (GlobalFreeBandwidthLimit, 14_400_000_000), 117 | (GlobalFreeBandwidthUsed, 0), 118 | (GlobalFreeBandwidthLatestSlot, 0), 119 | // Default: ChainParameter::TotalEnergyLimit / 14400, when accessed 120 | // (TotalEnergyTargetLimit, 90_000_000_000 / 14400) 121 | (TotalEnergyAverageUsage, 0), 122 | (TotalEnergyAverageSlot, 0), 123 | ]; 124 | } 125 | 126 | pub fn initial_value_hook( 127 | &self, 128 | params: &HashMap, 129 | _props: &HashMap, 130 | ) -> Option { 131 | match *self { 132 | DynamicProperty::TotalEnergyTargetLimit => Some(params[&ChainParameter::TotalEnergyLimit] / 14400), 133 | _ => None, 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /etc/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": 0, 3 | "parentHash": "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f", 4 | "witnesses": [ 5 | { 6 | "address": "THKJYuUmMKKARNf7s2VT51g5uPY6KEqnat", 7 | "url": "http://GR1.com", 8 | "votes": 100000026 9 | }, 10 | { 11 | "address": "TVDmPWGYxgi5DNeW8hXrzrhY8Y6zgxPNg4", 12 | "url": "http://GR2.com", 13 | "votes": 100000025 14 | }, 15 | { 16 | "address": "TWKZN1JJPFydd5rMgMCV5aZTSiwmoksSZv", 17 | "url": "http://GR3.com", 18 | "votes": 100000024 19 | }, 20 | { 21 | "address": "TDarXEG2rAD57oa7JTK785Yb2Et32UzY32", 22 | "url": "http://GR4.com", 23 | "votes": 100000023 24 | }, 25 | { 26 | "address": "TAmFfS4Tmm8yKeoqZN8x51ASwdQBdnVizt", 27 | "url": "http://GR5.com", 28 | "votes": 100000022 29 | }, 30 | { 31 | "address": "TK6V5Pw2UWQWpySnZyCDZaAvu1y48oRgXN", 32 | "url": "http://GR6.com", 33 | "votes": 100000021 34 | }, 35 | { 36 | "address": "TGqFJPFiEqdZx52ZR4QcKHz4Zr3QXA24VL", 37 | "url": "http://GR7.com", 38 | "votes": 100000020 39 | }, 40 | { 41 | "address": "TC1ZCj9Ne3j5v3TLx5ZCDLD55MU9g3XqQW", 42 | "url": "http://GR8.com", 43 | "votes": 100000019 44 | }, 45 | { 46 | "address": "TWm3id3mrQ42guf7c4oVpYExyTYnEGy3JL", 47 | "url": "http://GR9.com", 48 | "votes": 100000018 49 | }, 50 | { 51 | "address": "TCvwc3FV3ssq2rD82rMmjhT4PVXYTsFcKV", 52 | "url": "http://GR10.com", 53 | "votes": 100000017 54 | }, 55 | { 56 | "address": "TFuC2Qge4GxA2U9abKxk1pw3YZvGM5XRir", 57 | "url": "http://GR11.com", 58 | "votes": 100000016 59 | }, 60 | { 61 | "address": "TNGoca1VHC6Y5Jd2B1VFpFEhizVk92Rz85", 62 | "url": "http://GR12.com", 63 | "votes": 100000015 64 | }, 65 | { 66 | "address": "TLCjmH6SqGK8twZ9XrBDWpBbfyvEXihhNS", 67 | "url": "http://GR13.com", 68 | "votes": 100000014 69 | }, 70 | { 71 | "address": "TEEzguTtCihbRPfjf1CvW8Euxz1kKuvtR9", 72 | "url": "http://GR14.com", 73 | "votes": 100000013 74 | }, 75 | { 76 | "address": "TZHvwiw9cehbMxrtTbmAexm9oPo4eFFvLS", 77 | "url": "http://GR15.com", 78 | "votes": 100000012 79 | }, 80 | { 81 | "address": "TGK6iAKgBmHeQyp5hn3imB71EDnFPkXiPR", 82 | "url": "http://GR16.com", 83 | "votes": 100000011 84 | }, 85 | { 86 | "address": "TLaqfGrxZ3dykAFps7M2B4gETTX1yixPgN", 87 | "url": "http://GR17.com", 88 | "votes": 100000010 89 | }, 90 | { 91 | "address": "TX3ZceVew6yLC5hWTXnjrUFtiFfUDGKGty", 92 | "url": "http://GR18.com", 93 | "votes": 100000009 94 | }, 95 | { 96 | "address": "TYednHaV9zXpnPchSywVpnseQxY9Pxw4do", 97 | "url": "http://GR19.com", 98 | "votes": 100000008 99 | }, 100 | { 101 | "address": "TCf5cqLffPccEY7hcsabiFnMfdipfyryvr", 102 | "url": "http://GR20.com", 103 | "votes": 100000007 104 | }, 105 | { 106 | "address": "TAa14iLEKPAetX49mzaxZmH6saRxcX7dT5", 107 | "url": "http://GR21.com", 108 | "votes": 100000006 109 | }, 110 | { 111 | "address": "TBYsHxDmFaRmfCF3jZNmgeJE8sDnTNKHbz", 112 | "url": "http://GR22.com", 113 | "votes": 100000005 114 | }, 115 | { 116 | "address": "TEVAq8dmSQyTYK7uP1ZnZpa6MBVR83GsV6", 117 | "url": "http://GR23.com", 118 | "votes": 100000004 119 | }, 120 | { 121 | "address": "TRKJzrZxN34YyB8aBqqPDt7g4fv6sieemz", 122 | "url": "http://GR24.com", 123 | "votes": 100000003 124 | }, 125 | { 126 | "address": "TRMP6SKeFUt5NtMLzJv8kdpYuHRnEGjGfe", 127 | "url": "http://GR25.com", 128 | "votes": 100000002 129 | }, 130 | { 131 | "address": "TDbNE1VajxjpgM5p7FyGNDASt3UVoFbiD3", 132 | "url": "http://GR26.com", 133 | "votes": 100000001 134 | }, 135 | { 136 | "address": "TLTDZBcPoJ8tZ6TTEeEqEvwYFk2wgotSfD", 137 | "url": "http://GR27.com", 138 | "votes": 100000000 139 | } 140 | ], 141 | "allocs": [ 142 | { 143 | "name": "Zion", 144 | "address": "TLLM21wteSPs4hKjbxgmH1L6poyMjeTbHm", 145 | "balance": 99000000000000000 146 | }, 147 | { 148 | "name": "Sun", 149 | "address": "TXmVpin5vq5gdZsciyyjdZgKRUju4st1wM", 150 | "balance": 0 151 | }, 152 | { 153 | "name": "Blackhole", 154 | "address": "TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy", 155 | "balance": -9223372036854775808 156 | } 157 | ], 158 | "mantra": "A new system must allow existing systems to be linked together without requiring any central control or coordination", 159 | "creator": "7YxAaK71utTpYJ8u4Zna7muWxd1pQwimpGxy8" 160 | } 161 | -------------------------------------------------------------------------------- /etc/genesis.nile.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": 0, 3 | "parentHash": "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f", 4 | "witnesses": [ 5 | { 6 | "address": "TD23EqH3ixYMYh8CMXKdHyQWjePi3KQvxV", 7 | "url": "http://GR1.com", 8 | "votes": 100000026 9 | }, 10 | { 11 | "address": "TCm4Lz1uP3tQm3jzpwFTG6o5UvSTA2XEHc", 12 | "url": "http://GR2.com", 13 | "votes": 100000025 14 | }, 15 | { 16 | "address": "TTgDUgREiPBeY3iudD5e2eEibE4v4CE8C9", 17 | "url": "http://GR3.com", 18 | "votes": 100000024 19 | }, 20 | { 21 | "address": "TFVDe7kMEmb8EuUxxp42kocQY1fFY727WS", 22 | "url": "http://GR4.com", 23 | "votes": 100000023 24 | }, 25 | { 26 | "address": "TY4NSjctzTchHkhaCskVc5zQtnX9s1uxAX", 27 | "url": "http://GR5.com", 28 | "votes": 100000022 29 | }, 30 | { 31 | "address": "TWSMPrm6aizvsJmPnjMB7x3UExJfRhyQhd", 32 | "url": "http://GR6.com", 33 | "votes": 100000021 34 | }, 35 | { 36 | "address": "TKwLkSaCvqqpAB44qaHGTohCTCFoYw7ecy", 37 | "url": "http://GR7.com", 38 | "votes": 100000020 39 | }, 40 | { 41 | "address": "TDsYmm1St9r4UZebDGWBcTMtfYTw9YX5h4", 42 | "url": "http://GR8.com", 43 | "votes": 100000019 44 | }, 45 | { 46 | "address": "TFEQbWAPxhbUr1P14y9UJBUZo3LgtdqTS7", 47 | "url": "http://GR9.com", 48 | "votes": 100000018 49 | }, 50 | { 51 | "address": "TCynAi8tb7UWP7uhLv6fe971KLm2KT8tcs", 52 | "url": "http://GR10.com", 53 | "votes": 100000017 54 | }, 55 | { 56 | "address": "TC2YsLp4rzrt3AbeN3EryoSywrBjEUVCq3", 57 | "url": "http://GR11.com", 58 | "votes": 100000016 59 | }, 60 | { 61 | "address": "THxMKH1uaL5FpURujkQR7u2sNZ2n5PSsiH", 62 | "url": "http://GR12.com", 63 | "votes": 100000015 64 | }, 65 | { 66 | "address": "TWbzgoHimDcXWy19ts1An8bxA4JKjcYHeG", 67 | "url": "http://GR13.com", 68 | "votes": 100000014 69 | }, 70 | { 71 | "address": "TW2LmXnVCEaxuVtQN8gZR1ixT5PNm4QLft", 72 | "url": "http://GR14.com", 73 | "votes": 100000013 74 | }, 75 | { 76 | "address": "TVuqk4rYYVHVA6j6sSEnaLexhhoQhN8nyZ", 77 | "url": "http://GR15.com", 78 | "votes": 100000012 79 | }, 80 | { 81 | "address": "TVMZu5ptZPhhkZ3Kaagkq35FmyuKNvUKJV", 82 | "url": "http://GR16.com", 83 | "votes": 100000011 84 | }, 85 | { 86 | "address": "TFDHT8PqUrL2Bd8DeysSiHHBAEMidZgkhx", 87 | "url": "http://GR17.com", 88 | "votes": 100000010 89 | }, 90 | { 91 | "address": "TVqz5Bj3M1uEenaSsw2NnXvTWChPj6K3hb", 92 | "url": "http://GR18.com", 93 | "votes": 100000009 94 | }, 95 | { 96 | "address": "TSt8YNpARJkhdMdEV4C7ajH1tFHpZWzF1T", 97 | "url": "http://GR19.com", 98 | "votes": 100000008 99 | }, 100 | { 101 | "address": "TTxWDjEb3Be1Ax8BCvK48cnaorZofLq2C9", 102 | "url": "http://GR20.com", 103 | "votes": 100000007 104 | }, 105 | { 106 | "address": "TU5T838YtyZtEQKpnXEdRz3d8hJn6WHhjw", 107 | "url": "http://GR21.com", 108 | "votes": 100000006 109 | }, 110 | { 111 | "address": "TRuSs1MpL3o2hzhU8r6HLC7WtDyVE9hsF6", 112 | "url": "http://GR22.com", 113 | "votes": 100000005 114 | }, 115 | { 116 | "address": "TYMCoCZyAjWkWdUfEHg1oZQYbLKev282ou", 117 | "url": "http://GR23.com", 118 | "votes": 100000004 119 | }, 120 | { 121 | "address": "TQvAyGATpLZymHbpeaRozJCKqSeRWVNhCJ", 122 | "url": "http://GR24.com", 123 | "votes": 100000003 124 | }, 125 | { 126 | "address": "TYDd9nskbhJmLLNoe4yV2Z1SYtGjNa8wyg", 127 | "url": "http://GR25.com", 128 | "votes": 100000002 129 | }, 130 | { 131 | "address": "TS5991Geh2qeHtw46rskpJyn6hFNbuZGGc", 132 | "url": "http://GR26.com", 133 | "votes": 100000001 134 | }, 135 | { 136 | "address": "TKnn5MBnmXXeKdu9dxKVfKk4n1YdCeSRGr", 137 | "url": "http://GR27.com", 138 | "votes": 100000000 139 | } 140 | ], 141 | "allocs": [ 142 | { 143 | "name": "Zion", 144 | "address": "TMWXhuxiT1KczhBxCseCDDsrhmpYGUcoA9", 145 | "balance": 99000000000000000 146 | }, 147 | { 148 | "name": "Sun", 149 | "address": "TN21Wx2yoNYiZ7znuQonmZMJnH5Vdfxu78", 150 | "balance": 99000000000000000 151 | }, 152 | { 153 | "name": "Blackhole", 154 | "address": "TDPJULRzVtzVjnBmZvfaTcTNQ2tsVi6XxQ", 155 | "balance": -9223372036854775808 156 | } 157 | ], 158 | "mantra": "A new system must allow existing systems to be linked together without requiring any central control or coordination", 159 | "creator": "7YxAaK71utTpYJ8u4Zna7muWxd1pQwimpGxy8" 160 | } 161 | -------------------------------------------------------------------------------- /keys/src/private.rs: -------------------------------------------------------------------------------- 1 | //! The Private Key. 2 | 3 | use std::convert::TryFrom; 4 | use std::fmt; 5 | use std::str::FromStr; 6 | 7 | use hex::{FromHex, ToHex}; 8 | use libsecp256k1::{Message, SecretKey}; 9 | use sha2::{Digest, Sha256}; 10 | 11 | use crate::error::Error; 12 | use crate::signature::Signature; 13 | 14 | /// Private key of Secp256k1. 15 | #[derive(PartialEq, Hash, Clone)] 16 | pub struct Private([u8; 32]); 17 | 18 | impl Private { 19 | /// Sign digest data with the private key. 20 | pub fn sign_digest(&self, digest: &[u8]) -> Result { 21 | let secret_key = SecretKey::parse_slice(&self.0).expect("32 bytes, within curve order"); 22 | let message = Message::parse_slice(digest).map_err(|_| Error::InvalidMessage)?; 23 | let (sig, rec_id) = libsecp256k1::sign(&message, &secret_key); 24 | 25 | let mut raw = [0u8; 65]; 26 | raw[0..64].copy_from_slice(&sig.serialize()[..]); 27 | raw[64] = rec_id.serialize(); 28 | Ok(Signature::from(raw)) 29 | } 30 | 31 | /// Sign raw data with the private key. 32 | pub fn sign(&self, data: &[u8]) -> Result { 33 | let mut hasher = Sha256::new(); 34 | hasher.update(data); 35 | let digest = hasher.finalize(); 36 | 37 | self.sign_digest(&digest) 38 | } 39 | 40 | /// As raw bytes. 41 | pub fn as_bytes(&self) -> &[u8] { 42 | &self.0[..] 43 | } 44 | } 45 | 46 | impl fmt::Display for Private { 47 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | self.0.encode_hex::().fmt(f) 49 | } 50 | } 51 | 52 | impl fmt::Debug for Private { 53 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 54 | self.0.encode_hex::().fmt(f) 55 | } 56 | } 57 | 58 | impl TryFrom<&[u8]> for Private { 59 | type Error = Error; 60 | 61 | fn try_from(value: &[u8]) -> Result { 62 | if value.len() != 32 { 63 | Err(Error::InvalidPrivate) 64 | } else { 65 | let mut raw = [0u8; 32]; 66 | raw[..32].copy_from_slice(value); 67 | Ok(Private(raw)) 68 | } 69 | } 70 | } 71 | 72 | impl TryFrom> for Private { 73 | type Error = Error; 74 | 75 | fn try_from(value: Vec) -> Result { 76 | Self::try_from(&value[..]) 77 | } 78 | } 79 | 80 | impl TryFrom<&Vec> for Private { 81 | type Error = Error; 82 | 83 | fn try_from(value: &Vec) -> Result { 84 | Self::try_from(&value[..]) 85 | } 86 | } 87 | 88 | impl From<[u8; 32]> for Private { 89 | fn from(v: [u8; 32]) -> Self { 90 | Private(v) 91 | } 92 | } 93 | 94 | impl FromHex for Private { 95 | type Error = Error; 96 | 97 | fn from_hex>(hex: T) -> Result { 98 | Vec::from_hex(hex.as_ref()) 99 | .map_err(|_| Error::InvalidPrivate) 100 | .and_then(Self::try_from) 101 | } 102 | } 103 | 104 | impl FromStr for Private { 105 | type Err = Error; 106 | 107 | fn from_str(s: &str) -> Result 108 | where 109 | Self: Sized, 110 | { 111 | if s.len() == 64 { 112 | Vec::from_hex(s) 113 | .map_err(|_| Error::InvalidPrivate) 114 | .and_then(Self::try_from) 115 | } else if s.len() == 66 && s.starts_with("0x") { 116 | Vec::from_hex(&s.as_bytes()[2..]) 117 | .map_err(|_| Error::InvalidPrivate) 118 | .and_then(Self::try_from) 119 | } else { 120 | Err(Error::InvalidPrivate) 121 | } 122 | } 123 | } 124 | 125 | // NOTE: AsRef<[u8]> implies ToHex 126 | impl AsRef<[u8]> for Private { 127 | fn as_ref(&self) -> &[u8] { 128 | &self.0 129 | } 130 | } 131 | 132 | #[cfg(test)] 133 | mod tests { 134 | use super::*; 135 | 136 | #[test] 137 | fn test_private_sign() { 138 | let raw = Vec::from_hex( 139 | "0a0246742208f6a72da6712ec2a340d0fecbabf42d5a66080112620a2d747970652\ 140 | e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e7366657243\ 141 | 6f6e747261637412310a15419cf784b4cc7531f1598c4c322de9afdc597fe760121\ 142 | 541340967e825557559dc46bbf0eabe5ccf99fd134e18e80770cab0c8abf42d", 143 | ) 144 | .unwrap(); 145 | let priv_key: Private = "d705fc17c82942f85848ab522e42d986279028d09d12ad881bdc0e1327031976" 146 | .parse() 147 | .unwrap(); 148 | 149 | let sign = priv_key.sign(&raw).unwrap(); 150 | let sign2 = Signature::from_hex( 151 | "27ca15976a62ae3677d85f90e20d69d313ada17dba2a869fab3e3a10794f0ed62a6\ 152 | 7a711c6106de265adca72c95138be04f40e55d1c2ee76d5fa730f18ed790c01", 153 | ) 154 | .unwrap(); 155 | assert_eq!(sign, sign2); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /merkle-tree/src/tree.rs: -------------------------------------------------------------------------------- 1 | use types::H256; 2 | 3 | /// Binary Tree where leaves hold a stand-alone value. 4 | #[derive(Clone, Debug, PartialEq)] 5 | pub enum Tree { 6 | Empty { 7 | hash: H256, 8 | }, 9 | 10 | Leaf { 11 | hash: H256, 12 | value: T, 13 | }, 14 | 15 | Node { 16 | hash: H256, 17 | left: Box>, 18 | right: Box>, 19 | }, 20 | } 21 | 22 | impl Tree { 23 | /// Create an empty tree 24 | pub fn empty(hash: H256) -> Self { 25 | Tree::Empty { hash: hash } 26 | } 27 | 28 | /// Create a new tree 29 | pub fn new(hash: H256, value: T) -> Self { 30 | Tree::Leaf { 31 | hash: hash, 32 | value: value, 33 | } 34 | } 35 | 36 | /// Create a new leaf 37 | /* 38 | pub fn new_leaf(algo: &'static Algorithm, value: T) -> Tree 39 | where 40 | T: Hashable, 41 | { 42 | let hash = algo.hash_leaf(&value); 43 | Tree::new(hash, value) 44 | } 45 | */ 46 | 47 | /// Returns a hash from the tree. 48 | pub fn hash(&self) -> &H256 { 49 | match *self { 50 | Tree::Empty { ref hash } => hash, 51 | Tree::Leaf { ref hash, .. } => hash, 52 | Tree::Node { ref hash, .. } => hash, 53 | } 54 | } 55 | 56 | /// Returns a borrowing iterator over the leaves of the tree. 57 | pub fn iter(&self) -> LeavesIterator { 58 | LeavesIterator::new(self) 59 | } 60 | } 61 | 62 | /// An borrowing iterator over the leaves of a `Tree`. 63 | /// Adapted from http://codereview.stackexchange.com/q/110283. 64 | #[allow(missing_debug_implementations)] 65 | pub struct LeavesIterator<'a, T> 66 | where 67 | T: 'a, 68 | { 69 | current_value: Option<&'a T>, 70 | right_nodes: Vec<&'a Tree>, 71 | } 72 | 73 | impl<'a, T> LeavesIterator<'a, T> { 74 | fn new(root: &'a Tree) -> Self { 75 | let mut iter = LeavesIterator { 76 | current_value: None, 77 | right_nodes: Vec::new(), 78 | }; 79 | 80 | iter.add_left(root); 81 | 82 | iter 83 | } 84 | 85 | fn add_left(&mut self, mut tree: &'a Tree) { 86 | loop { 87 | match *tree { 88 | Tree::Empty { .. } => { 89 | self.current_value = None; 90 | break; 91 | } 92 | 93 | Tree::Node { 94 | ref left, ref right, .. 95 | } => { 96 | self.right_nodes.push(right); 97 | tree = left; 98 | } 99 | 100 | Tree::Leaf { ref value, .. } => { 101 | self.current_value = Some(value); 102 | break; 103 | } 104 | } 105 | } 106 | } 107 | } 108 | 109 | impl<'a, T> Iterator for LeavesIterator<'a, T> { 110 | type Item = &'a T; 111 | 112 | fn next(&mut self) -> Option<&'a T> { 113 | let result = self.current_value.take(); 114 | 115 | if let Some(rest) = self.right_nodes.pop() { 116 | self.add_left(rest); 117 | } 118 | 119 | result 120 | } 121 | } 122 | 123 | /// An iterator over the leaves of a `Tree`. 124 | #[allow(missing_debug_implementations)] 125 | pub struct LeavesIntoIterator { 126 | current_value: Option, 127 | right_nodes: Vec>, 128 | } 129 | 130 | impl LeavesIntoIterator { 131 | fn new(root: Tree) -> Self { 132 | let mut iter = LeavesIntoIterator { 133 | current_value: None, 134 | right_nodes: Vec::new(), 135 | }; 136 | 137 | iter.add_left(root); 138 | 139 | iter 140 | } 141 | 142 | fn add_left(&mut self, mut tree: Tree) { 143 | loop { 144 | match tree { 145 | Tree::Empty { .. } => { 146 | self.current_value = None; 147 | break; 148 | } 149 | 150 | Tree::Node { left, right, .. } => { 151 | self.right_nodes.push(*right); 152 | tree = *left; 153 | } 154 | 155 | Tree::Leaf { value, .. } => { 156 | self.current_value = Some(value); 157 | break; 158 | } 159 | } 160 | } 161 | } 162 | } 163 | 164 | impl Iterator for LeavesIntoIterator { 165 | type Item = T; 166 | 167 | fn next(&mut self) -> Option { 168 | let result = self.current_value.take(); 169 | 170 | if let Some(rest) = self.right_nodes.pop() { 171 | self.add_left(rest); 172 | } 173 | 174 | result 175 | } 176 | } 177 | 178 | impl IntoIterator for Tree { 179 | type Item = T; 180 | type IntoIter = LeavesIntoIterator; 181 | 182 | fn into_iter(self) -> Self::IntoIter { 183 | LeavesIntoIterator::new(self) 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /proto/src/contract_ext.rs: -------------------------------------------------------------------------------- 1 | //! Extension for handling builtin contract types. 2 | //! 3 | //! ``` 4 | //! let transfer_contract = TransferContract { 5 | //! owner_address: "..." 6 | //! to_address: "..." 7 | //! amount: 100000 8 | //! }; 9 | //! let raw = TransactionRaw { 10 | //! contract: Some(transfer_contract.into()), 11 | //! ..Default::default() 12 | //! }; 13 | //! ``` 14 | 15 | use crate::chain::transaction::Contract; 16 | use crate::chain::ContractType; 17 | use prost::Message; 18 | use prost_types::Any; 19 | 20 | pub trait ContractExt: Message + Default + Sized { 21 | fn owner_address(&self) -> &[u8]; 22 | 23 | fn type_code(&self) -> ContractType; 24 | 25 | fn from_any(any: &Any) -> Option { 26 | Self::decode(&any.value[..]).ok() 27 | } 28 | 29 | fn to_any(&self) -> Option { 30 | let mut buf = Vec::with_capacity(255); 31 | self.encode(&mut buf).ok()?; 32 | Some(Any { 33 | type_url: format!("type.googleapis.com/protocol.{:?}", self.type_code()), 34 | value: buf, 35 | }) 36 | } 37 | } 38 | 39 | /// Impl ContractExt for builtin contract protobufs. 40 | macro_rules! impl_contract_ext_for { 41 | ($contract_ty:ident) => { 42 | impl ContractExt for $crate::contract::$contract_ty { 43 | fn owner_address(&self) -> &[u8] { 44 | &self.owner_address 45 | } 46 | fn type_code(&self) -> ContractType { 47 | ContractType::$contract_ty 48 | } 49 | } 50 | 51 | impl From<$crate::contract::$contract_ty> for Contract { 52 | fn from(inner_cntr: $crate::contract::$contract_ty) -> Self { 53 | Contract { 54 | r#type: ContractType::$contract_ty as i32, 55 | parameter: inner_cntr.to_any(), 56 | ..Default::default() 57 | } 58 | } 59 | } 60 | }; 61 | ($contract_ty:ident, $type_name:expr) => { 62 | impl ContractExt for $crate::contract::$contract_ty { 63 | fn owner_address(&self) -> &[u8] { 64 | &self.owner_address 65 | } 66 | fn type_code(&self) -> ContractType { 67 | ContractType::$contract_ty 68 | } 69 | fn to_any(&self) -> Option { 70 | let mut buf = Vec::with_capacity(255); 71 | self.encode(&mut buf).ok()?; 72 | Some(Any { 73 | type_url: format!("type.googleapis.com/protocol.{:?}", $type_name), 74 | value: buf, 75 | }) 76 | } 77 | } 78 | 79 | impl From<$crate::contract::$contract_ty> for Contract { 80 | fn from(inner_cntr: $crate::contract::$contract_ty) -> Self { 81 | Contract { 82 | r#type: ContractType::$contract_ty as i32, 83 | parameter: inner_cntr.to_any(), 84 | ..Default::default() 85 | } 86 | } 87 | } 88 | }; 89 | } 90 | 91 | impl_contract_ext_for!(AccountCreateContract); 92 | impl_contract_ext_for!(AccountUpdateContract); 93 | impl_contract_ext_for!(SetAccountIdContract); 94 | impl_contract_ext_for!(AccountPermissionUpdateContract); 95 | impl_contract_ext_for!(TransferContract); 96 | impl_contract_ext_for!(TransferAssetContract); 97 | impl_contract_ext_for!(AssetIssueContract); 98 | impl_contract_ext_for!(ParticipateAssetIssueContract); 99 | // NOTE: VoteAssetContract is not used in java-tron. 100 | // impl_contract_ext_for!(VoteAssetContract); 101 | impl_contract_ext_for!(UpdateAssetContract); 102 | impl_contract_ext_for!(UnfreezeAssetContract); 103 | impl_contract_ext_for!(WitnessCreateContract); 104 | impl_contract_ext_for!(WitnessUpdateContract); 105 | impl_contract_ext_for!(UpdateBrokerageContract); 106 | impl_contract_ext_for!(VoteWitnessContract); 107 | impl_contract_ext_for!(WithdrawBalanceContract); 108 | impl_contract_ext_for!(CreateSmartContract); 109 | impl_contract_ext_for!(TriggerSmartContract); 110 | impl_contract_ext_for!(UpdateSettingContract); 111 | impl_contract_ext_for!(UpdateEnergyLimitContract); 112 | // prost will rename enum variant to CamelCase. 113 | impl_contract_ext_for!(ClearAbiContract, "ClearABIContract"); 114 | impl_contract_ext_for!(FreezeBalanceContract); 115 | impl_contract_ext_for!(UnfreezeBalanceContract); 116 | impl_contract_ext_for!(ProposalCreateContract); 117 | impl_contract_ext_for!(ProposalApproveContract); 118 | impl_contract_ext_for!(ProposalDeleteContract); 119 | impl_contract_ext_for!(ExchangeCreateContract); 120 | impl_contract_ext_for!(ExchangeInjectContract); 121 | impl_contract_ext_for!(ExchangeWithdrawContract); 122 | impl_contract_ext_for!(ExchangeTransactionContract); 123 | 124 | #[cfg(feature = "nile")] 125 | impl ContractExt for ::proto::contract::ShieldedTransferContract { 126 | fn owner_address(&self) -> &[u8] { 127 | &[] 128 | } 129 | fn type_code(&self) -> ContractType { 130 | ContractType::ShieldedTransferContract 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use chrono::Utc; 2 | use clap::ArgMatches; 3 | use crypto::sha256; 4 | use keys::{Address, KeyPair}; 5 | use prost::Message; 6 | use proto::chain::transaction::{Contract, Raw as TransactionRaw}; 7 | use proto::contract as contract_pb; 8 | 9 | mod account; 10 | mod proposal; 11 | mod system; 12 | mod util; 13 | mod witness; 14 | 15 | pub(crate) type Result = std::result::Result>; 16 | 17 | pub(crate) fn custom_error(msg: &str) -> Box { 18 | Box::new(std::io::Error::new(std::io::ErrorKind::Other, msg)) 19 | } 20 | 21 | fn main() -> Result<()> { 22 | let yaml = clap::load_yaml!("cli.yml"); 23 | let matches = clap::App::from_yaml(yaml).get_matches(); 24 | 25 | let cntr = match matches.subcommand() { 26 | ("transfer", Some(arg_matches)) => transfer(arg_matches), 27 | ("account", Some(arg_matches)) => account::main(arg_matches), 28 | ("witness", Some(arg_matches)) => witness::main(arg_matches), 29 | ("system", Some(arg_matches)) => system::main(arg_matches), 30 | ("proposal", Some(arg_matches)) => proposal::main(arg_matches).ok(), 31 | // TODO: 32 | // ("exchange", Some(arg_matches)) => exchange::main(arg_matches).ok(), 33 | // ("market", Some(arg_matches)) => market::main(arg_matches).ok(), 34 | 35 | // commands::transfer::main(arg_matches), 36 | // ("list", Some(arg_matches)) => commands::list::main(arg_matches), 37 | _ => unimplemented!(), 38 | }; 39 | 40 | pack_and_send(cntr.expect("illegal contract"), &matches) 41 | } 42 | 43 | fn transfer(matches: &ArgMatches) -> Option { 44 | let from: Address = matches.value_of("SENDER")?.parse().ok()?; 45 | let to: Address = matches.value_of("RECIPIENT")?.parse().ok()?; 46 | let amount = util::parse_amount_with_currency(matches.value_of("AMOUNT")?, "TRX", 6)?; 47 | 48 | let transfer = contract_pb::TransferContract { 49 | owner_address: from.as_bytes().to_vec(), 50 | to_address: to.as_bytes().to_vec(), 51 | amount: amount, 52 | }; 53 | 54 | Some(transfer.into()) 55 | } 56 | 57 | fn pack_and_send(cntr: Contract, matches: &ArgMatches) -> Result<()> { 58 | let ref_block_hash = get_ref_block_hash(matches)?; 59 | 60 | let raw = TransactionRaw { 61 | contract: Some(cntr), 62 | ref_block_bytes: ref_block_hash[6..8].to_vec(), 63 | ref_block_hash: ref_block_hash[8..16].to_vec(), 64 | expiration: Utc::now().timestamp_millis() + 60_000, 65 | ..Default::default() 66 | }; 67 | let mut buf = Vec::with_capacity(255); 68 | raw.encode(&mut buf)?; 69 | 70 | let hex_priv_key = matches.value_of("private-key").unwrap(); 71 | let kp = KeyPair::from_private(hex_priv_key.parse()?)?; 72 | 73 | let sig = kp.private().sign(&buf)?; 74 | 75 | println!("RAW => {}", hex::encode(&buf)); 76 | println!("TXN Hash => {:?}", sha256(&buf)); 77 | println!("SIG => {}", hex::encode(sig.as_bytes())); 78 | 79 | if !matches.is_present("dont-broadcast") { 80 | send_raw_transaction(&hex::encode(&buf), &hex::encode(sig.as_bytes()), matches)?; 81 | } 82 | 83 | Ok(()) 84 | } 85 | 86 | fn send_raw_transaction(raw: &str, signature: &str, matches: &ArgMatches) -> Result<()> { 87 | let rpc_url = matches.value_of("rpc-url").expect("has default; qed"); 88 | 89 | let client = reqwest::blocking::Client::new(); 90 | let mutation = r#"{ "query": "mutation { txn: sendRawTransaction(rawData: \"RAW\", signatures: [\"SIG\"]) }" }"#; 91 | 92 | let mutation = mutation.replace("RAW", raw).replace("SIG", signature); 93 | let resp = client 94 | .post(rpc_url) 95 | .header("User-Agent", "Opentron Cli/0.1.0") 96 | .header("Accept", "application/json") 97 | .header("Content-Type", "application/json") 98 | .body(mutation) 99 | .send()?; 100 | 101 | let payload: serde_json::Value = resp.json()?; 102 | 103 | println!("{}", serde_json::to_string_pretty(&payload)?); 104 | if !payload["data"].is_null() { 105 | let hash = &payload["data"]["txn"]; 106 | println!("Broadcast => {}", hash); 107 | } else { 108 | println!("! Broadcast ERROR"); 109 | } 110 | Ok(()) 111 | } 112 | 113 | fn get_ref_block_hash(matches: &ArgMatches) -> Result> { 114 | let rpc_url = matches.value_of("rpc-url").expect("has default; qed"); 115 | 116 | let client = reqwest::blocking::Client::new(); 117 | // "operationName":null, 118 | // "variables":{}, 119 | let query = r#"{ 120 | "query":"{ refBlock: block { hash } }" 121 | }"#; 122 | let resp = client 123 | .post(rpc_url) 124 | .header("User-Agent", "Opentron Cli/0.1.0") 125 | .header("Accept", "application/json") 126 | .header("Content-Type", "application/json") 127 | .body(query) 128 | .send()?; 129 | 130 | let payload: serde_json::Value = resp.json()?; 131 | 132 | // println!("{}", serde_json::to_string_pretty(&payload)?); 133 | let hash = &payload["data"]["refBlock"]["hash"]; 134 | println!("Ref Block Hash => {}", hash.as_str().unwrap()); 135 | hex::decode(hash.as_str().unwrap()).map_err(From::from) 136 | } 137 | -------------------------------------------------------------------------------- /keys/src/signature.rs: -------------------------------------------------------------------------------- 1 | //! A signature signed by some private key. 2 | use std::iter; 3 | use std::{fmt, ops, str}; 4 | 5 | use hex::{FromHex, ToHex}; 6 | use std::convert::TryFrom; 7 | 8 | use crate::error::Error; 9 | 10 | /// A Signature of Secp256k1. The `v`(rec_id) is different from Ethereum. 11 | #[derive(Clone)] 12 | pub struct Signature([u8; 65]); 13 | 14 | impl Signature { 15 | /// Get a slice into the 'r' portion of the data. 16 | pub fn r(&self) -> &[u8] { 17 | &self.0[0..32] 18 | } 19 | 20 | /// Get a slice into the 's' portion of the data. 21 | pub fn s(&self) -> &[u8] { 22 | &self.0[32..64] 23 | } 24 | 25 | /// Get the recovery byte. 26 | pub fn v(&self) -> u8 { 27 | self.0[64] 28 | } 29 | 30 | /// Check if this is a "low" signature (that s part of the signature is in range 31 | /// 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive)). 32 | /// This condition may be required by some verification algorithms 33 | pub fn is_low_s(&self) -> bool { 34 | const LOW_SIG_THRESHOLD: [u8; 32] = [ 35 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5D, 0x57, 36 | 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0, 37 | ]; 38 | self.s() <= &LOW_SIG_THRESHOLD[..] 39 | } 40 | 41 | /// As raw signature bytes. 42 | pub fn as_bytes(&self) -> &[u8] { 43 | &self.0[..] 44 | } 45 | } 46 | 47 | impl PartialEq for Signature { 48 | fn eq(&self, other: &Self) -> bool { 49 | self.0[..] == other.0[..] 50 | } 51 | } 52 | 53 | // also manual for the same reason, but the pretty printing might be useful. 54 | impl fmt::Debug for Signature { 55 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 56 | f.debug_struct("Signature") 57 | .field("r", &(&self.0[0..32]).encode_hex::()) 58 | .field("s", &(&self.0[32..64]).encode_hex::()) 59 | .field("v", &(&self.0[64..65]).encode_hex::()) 60 | .finish() 61 | } 62 | } 63 | 64 | impl fmt::Display for Signature { 65 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 66 | (&self.0[..]).encode_hex::().fmt(f) 67 | } 68 | } 69 | 70 | impl ops::Deref for Signature { 71 | type Target = [u8]; 72 | 73 | fn deref(&self) -> &Self::Target { 74 | &self.0 75 | } 76 | } 77 | 78 | impl str::FromStr for Signature { 79 | type Err = Error; 80 | 81 | fn from_str(s: &str) -> Result { 82 | Vec::from_hex(s) 83 | .map_err(|_| Error::InvalidSignature) 84 | .and_then(Signature::try_from) 85 | } 86 | } 87 | 88 | impl TryFrom<&'static str> for Signature { 89 | type Error = Error; 90 | 91 | fn try_from(s: &'static str) -> Result { 92 | s.parse() 93 | } 94 | } 95 | 96 | impl<'a> TryFrom<&'a [u8]> for Signature { 97 | type Error = Error; 98 | 99 | fn try_from(mut v: &'a [u8]) -> Result { 100 | if v.len() > 65 { 101 | // NOTE: a8f55980f7312adf9bd67b9436d362599cb2f5b83d255435cf5dbdc6bd1eaacd 102 | // with signature: 103 | // 2d206c63fad7b7130845c3bfbaf75c057054596619ab5725078e248717c9605a (r) 104 | // 3c52f496e230a0cdbdf63e443ee7839ceb21ac348e6e69be1470fa37fac89550 (s) 105 | // 01 (v) 106 | // 9000 (rubbish surfix) 107 | v = &v[..65]; 108 | } 109 | if v.len() == 65 { 110 | let mut inner = [0u8; 65]; 111 | (&mut inner[..]).copy_from_slice(v); 112 | // NOTE: 0x2fe5b7a5610aa9dc081574b0451af82ac586ac0a67e2da2a100a5923c862e357 113 | if inner[64] >= 27 { 114 | inner[64] -= 27; 115 | } 116 | Ok(Signature(inner)) 117 | } else { 118 | Err(Error::InvalidSignature) 119 | } 120 | } 121 | } 122 | 123 | impl TryFrom> for Signature { 124 | type Error = Error; 125 | 126 | fn try_from(v: Vec) -> Result { 127 | Signature::try_from(&v[..]) 128 | } 129 | } 130 | 131 | impl TryFrom<&Vec> for Signature { 132 | type Error = Error; 133 | 134 | fn try_from(v: &Vec) -> Result { 135 | Signature::try_from(&v[..]) 136 | } 137 | } 138 | 139 | impl From<[u8; 65]> for Signature { 140 | fn from(v: [u8; 65]) -> Self { 141 | Signature(v) 142 | } 143 | } 144 | 145 | impl FromHex for Signature { 146 | type Error = Error; 147 | 148 | fn from_hex>(hex: T) -> Result { 149 | Vec::from_hex(hex.as_ref()) 150 | .map_err(|_| Error::InvalidSignature) 151 | .and_then(Self::try_from) 152 | } 153 | } 154 | 155 | impl ToHex for Signature { 156 | fn encode_hex>(&self) -> T { 157 | (&self.0[..]).encode_hex() 158 | } 159 | 160 | fn encode_hex_upper>(&self) -> T { 161 | (&self.0[..]).encode_hex_upper() 162 | } 163 | } 164 | 165 | impl From for Vec { 166 | fn from(s: Signature) -> Self { 167 | (&s.0[..]).to_owned() 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /docs/networks.md: -------------------------------------------------------------------------------- 1 | # All networks 2 | 3 | ## Mainnet 4 | 5 | 🔍Explorer: 6 | 7 | - 8 | - 9 | - 10 | 11 | TronGrid API / Full Node API / Event API: 12 | 13 | - (load balanced of following) 14 | - 15 | - 16 | - 17 | 18 | Full Node API: 19 | 20 | Tronscan API: 21 | 22 | gRPC: grpc.trongrid.io:50051 23 | 24 | Public Full Node: 25 | 26 | ```text 27 | 3.225.171.164 28 | 52.53.189.99 29 | 18.196.99.16 30 | 34.253.187.192 31 | 52.56.56.149 32 | 35.180.51.163 33 | 54.252.224.209 34 | 18.228.15.36 35 | 52.15.93.92 36 | 34.220.77.106 37 | 13.127.47.162 38 | 13.124.62.58 39 | 35.182.229.162 40 | 18.209.42.127 41 | 3.218.137.187 42 | 34.237.210.82 43 | ``` 44 | 45 | Data backup: 46 | 47 | - LevelDB with internalTx, old backups will be deleted more frequently 48 | - LevelDB 49 | - RocksDB 50 | 51 | ## Shasta Testnet 52 | 53 | NOTE: You can NOT join the Shasta testnet. 54 | 55 | Home page: 56 | 57 | 🚰Faucet: 58 | 59 | 🔍Explorer: 60 | 61 | TronGrid API / Full Node API / Event API: 62 | 63 | Tronscan API: 64 | 65 | gRPC: grpc.shasta.trongrid.io:50051 66 | 67 | ## Nile Testnet 68 | 69 | NOTE: Nile uses newer test branch than the Mainnet. 70 | 71 | Home page: 72 | 73 | 🚰Faucet: 74 | 75 | 🔍Explorer: 76 | 77 | 🩺Status: 78 | 79 | Full Node API: 80 | 81 | Event API: 82 | 83 | Tronscan API: 84 | 85 | Public Fullnode: 86 | 87 | - 47.252.19.181 88 | - 47.252.3.238 89 | 90 | Data backup: 91 | 92 | - 93 | 94 | ## Tronex Testnet 95 | 96 | NOTE: This testnet MUST be synced from backup data. 97 | 98 | NOTE: This testnet has a dappchain testnet side-chain. 99 | 100 | Home page: 101 | 102 | 🚰Faucet: 103 | 104 | 🔍Explorer: 105 | 106 | 🩺Status: 107 | 108 | Full Node API: 109 | 110 | Event API: 111 | 112 | Public Fullnode 113 | 114 | - 47.252.87.28 115 | - 47.252.85.13 116 | 117 | Data backup: 118 | 119 | - 120 | 121 | ## DAppChain (SUN Network) 122 | 123 | Home page: 124 | 125 | 🔍Explorer: 126 | 127 | Event Server: 128 | 129 | NOTE: event listening is via: 130 | > 131 | 132 | ### Cross Chain 133 | 134 | SideChainID 135 | > 41E209E4DE650F0150788E8EC5CAFA240A23EB8EB7 136 | 137 | TRON Network MainChain gateway contract address 138 | > TWaPZru6PR5VjgT4sJrrZ481Zgp3iJ8Rfo 139 | 140 | SUN Network DAppChain(SideChain) gateway contract address 141 | > TGKotco6YoULzbYisTBuP6DWXDjEgJSpYz 142 | 143 | ### Full Nodes 144 | 145 | HTTP API: 146 | 147 | - (CORS enabled) 148 | - 47.90.245.159:8090 149 | - 47.90.211.50:8090 150 | - 47.252.6.19:8090 151 | - 47.89.185.14:8090 152 | 153 | gRPC: 154 | 155 | - 47.90.245.159:50051 156 | - 47.90.211.50:50051 157 | - 47.252.6.19:50051 158 | - 47.89.185.14:50051 159 | 160 | ### Solidity Nodes 161 | 162 | HTTP API 163 | 164 | - sun.tronex.io/walletsolidity (CORS enabled) 165 | - 47.90.245.159:8091 166 | - 47.90.211.50:8091 167 | - 47.252.6.19:8091 168 | - 47.89.185.14:8091 169 | 170 | gRPC: 171 | 172 | - 47.90.245.159:50061 173 | - 47.90.211.50:50061 174 | - 47.252.6.19:50061 175 | - 47.89.185.14:50061 176 | 177 | ## DAppChain Testnet (SUN Network Testnet) 178 | 179 | Home page: 180 | 181 | Faucet: Use to get main-chain coin. 182 | 183 | Event Server: 184 | 185 | - (CORS Enabled) - main chain 186 | - (CORS Enabled) - side chain 187 | - (CORS Enabled) - side chain 188 | 189 | NOTE: event listening is via: 190 | > 191 | 192 | ### Testnet Cross Chain 193 | 194 | sidechainid 195 | > 413AF23F37DA0D48234FDD43D89931E98E1144481B 196 | 197 | main chain gateway contract address 198 | > TFLtPoEtVJBMcj6kZPrQrwEdM3W3shxsBU 199 | 200 | side chain gateway contract address 201 | > TRDepx5KoQ8oNbFVZ5sogwUxtdYmATDRgX 202 | 203 | ### Testnet Full Nodes 204 | 205 | HTTP API: 206 | 207 | - 47.252.85.90:8090 208 | - 47.252.85.90:8070(CORS Enabled) 209 | - 47.252.80.185:8090 210 | - 47.252.84.141:8090 211 | 212 | gRPC: 213 | 214 | - 47.252.85.90:50051 215 | - 47.252.80.185:50051 216 | - 47.252.84.141:50051 217 | 218 | ### Solidity Notes 219 | 220 | HTTP API: 221 | 222 | - 47.252.85.90:8091 223 | - 47.252.85.90:8071(CORS Enabled) 224 | - 47.252.80.185:8091 225 | - 47.252.84.141:8091 226 | 227 | RPC Interface 228 | 229 | - 47.252.85.90:50060 230 | - 47.252.80.185:50060 231 | - 47.252.84.141:50060 232 | -------------------------------------------------------------------------------- /opentron/src/main.rs: -------------------------------------------------------------------------------- 1 | // NOTE: Embedding slog macros and select! requires increasing recursion_limit. 2 | #![recursion_limit = "1024"] 3 | use std::error::Error; 4 | use std::sync::atomic::Ordering; 5 | use std::sync::{Arc, Mutex}; 6 | 7 | use futures::channel::oneshot; 8 | use futures::join; 9 | use log::info; 10 | use slog::{o, slog_debug, slog_info, Drain}; 11 | use slog_scope_futures::FutureExt as SlogFutureExt; 12 | 13 | use channel_service::server::channel_server; 14 | use context::AppContext; 15 | use discovery_service::server::discovery_server; 16 | use graphql_service::server::graphql_server; 17 | use opentron::util::get_my_ip; 18 | use producer_service::producer_task; 19 | 20 | fn main() -> Result<(), Box> { 21 | // ! init app command line arguments 22 | let yaml = clap::load_yaml!("cli.yml"); 23 | let matches = clap::App::from_yaml(yaml).get_matches(); 24 | 25 | match matches.subcommand() { 26 | ("key", Some(arg_matches)) => { 27 | opentron::commands::key::main(arg_matches)?; 28 | return Ok(()); 29 | } 30 | _ => (), 31 | } 32 | 33 | // ! init loggers 34 | let decorator = slog_term::TermDecorator::new().build(); 35 | // let drain = slog_term::CompactFormat::new(decorator).build().fuse(); 36 | let drain = slog_term::FullFormat::new(decorator).build().fuse(); 37 | let drain = slog_async::Async::new(drain).build().fuse(); 38 | let drain = if matches.is_present("debug") { 39 | slog::LevelFilter(drain, slog::Level::Debug).fuse() 40 | } else { 41 | slog::LevelFilter(drain, slog::Level::Info).fuse() 42 | }; 43 | 44 | let logger = slog::Logger::root(drain, o!()); 45 | 46 | let _scope_guard = slog_scope::set_global_logger(logger); 47 | let _log_guard = slog_stdlog::init().unwrap(); 48 | 49 | let config_file = matches.value_of("config").expect("has default in cli.yml; qed"); 50 | 51 | // ! #[tokio::main] runner 52 | let rt = tokio::runtime::Builder::new_multi_thread() 53 | .worker_threads(num_cpus::get_physical()) 54 | .thread_name("tokio-pool") 55 | .enable_all() 56 | .build()?; 57 | 58 | slog_info!(slog_scope::logger(), "use config file"; "path" => config_file); 59 | let mut ctx = AppContext::from_config(config_file)?; 60 | let outbound_ip = get_my_ip().unwrap_or("127.0.0.1".into()); 61 | info!("outbound ip address: {}", outbound_ip); 62 | ctx.outbound_ip = outbound_ip; 63 | 64 | slog_debug!(slog_scope::logger(), "loaded config"; "config" => format!("{:#?}", ctx.config)); 65 | 66 | match matches.subcommand() { 67 | ("check", Some(arg_matches)) => { 68 | let fut = opentron::commands::check::main(ctx, arg_matches); 69 | rt.block_on(fut) 70 | } 71 | ("fix", Some(arg_matches)) => { 72 | let fut = opentron::commands::fix::main(ctx, arg_matches); 73 | rt.block_on(fut) 74 | } 75 | ("dev", Some(_)) => { 76 | let fut = opentron::commands::dev::main(ctx); 77 | rt.block_on(fut) 78 | } 79 | _ => { 80 | let fut = run(ctx); 81 | rt.block_on(fut) 82 | } 83 | } 84 | } 85 | 86 | // NOTE: #[tokio::main] conflicts with slog_scope, cause data race in global static resource release. 87 | async fn run(ctx: AppContext) -> Result<(), Box> { 88 | let ctx = Arc::new(ctx); 89 | 90 | let (termination_tx, termination_done) = oneshot::channel::<()>(); 91 | let termination_handler = { 92 | let ctx = ctx.clone(); 93 | move || { 94 | ctx.running.store(false, Ordering::SeqCst); 95 | ctx.chain_db.report_status(); 96 | let _ = ctx.termination_signal.send(()); 97 | unsafe { 98 | ctx.chain_db.prepare_close(); 99 | } 100 | let _ = termination_tx.send(()); 101 | } 102 | }; 103 | 104 | let f = Mutex::new(Some(termination_handler)); 105 | ctrlc::set_handler(move || { 106 | eprintln!("\nCtrl-C pressed. Now shuting down gracefully... "); 107 | if let Ok(mut guard) = f.lock() { 108 | if let Some(f) = guard.take() { 109 | f(); 110 | } else { 111 | eprintln!("\nCtrl-C pressed again, be patient!"); 112 | } 113 | } 114 | }) 115 | .expect("Error setting Ctrl-C handler"); 116 | 117 | let graphql_service = { 118 | let ctx = ctx.clone(); 119 | let done_signal = ctx.termination_signal.subscribe(); 120 | let logger = slog_scope::logger().new(o!("service" => "graphql")); 121 | graphql_server(ctx, done_signal).with_logger(logger) 122 | }; 123 | 124 | let channel_service = { 125 | let ctx = ctx.clone(); 126 | let done_signal = ctx.termination_signal.subscribe(); 127 | channel_server(ctx, done_signal) 128 | }; 129 | 130 | let discovery_service = { 131 | let ctx = ctx.clone(); 132 | let done_signal = ctx.termination_signal.subscribe(); 133 | let logger = slog_scope::logger().new(o!("service" => "discovery")); 134 | discovery_server(ctx, done_signal).with_logger(logger) 135 | }; 136 | 137 | let producer_task = { 138 | let ctx = ctx.clone(); 139 | let done_signal = ctx.termination_signal.subscribe(); 140 | producer_task(ctx, done_signal) 141 | }; 142 | 143 | let _ = join!(graphql_service, channel_service, discovery_service, producer_task); 144 | 145 | Ok(termination_done.await?) 146 | } 147 | --------------------------------------------------------------------------------