Просмотр исходного кода

initial basic dao mint in wasm

x 3 лет назад
Родитель
Сommit
14807bcde6

+ 1 - 1
example/dao2/contract/dao/Cargo.toml

@@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
 
 [dependencies]
 darkfi-sdk = { path = "../../../../src/sdk" }
-darkfi-serial = { path = "../../../../src/serial" }
+darkfi-serial = { path = "../../../../src/serial", features = ["crypto"] }
 
 # We need to disable random using "custom" which makes the crate a noop
 # so the wasm32-unknown-unknown target is enabled.

+ 71 - 8
example/dao2/contract/dao/src/lib.rs

@@ -1,14 +1,23 @@
 use darkfi_sdk::{
-    crypto::ContractId,
+    crypto::{ContractId, constants::MERKLE_DEPTH, MerkleNode, Nullifier},
     db::{db_get, db_init, db_lookup, db_set},
     define_contract,
     error::ContractResult,
     msg,
+    merkle::merkle_add,
     pasta::pallas,
     tx::ContractCall,
-    util::{set_return_data, put_object_bytes, get_object_bytes, get_object_size},
+    util::{get_object_bytes, get_object_size, put_object_bytes, set_return_data},
+    incrementalmerkletree::{bridgetree::BridgeTree, Tree}
 };
-use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable, WriteExt, ReadExt};
+use darkfi_serial::{
+    deserialize, serialize, Encodable, ReadExt, SerialDecodable, SerialEncodable, WriteExt,
+};
+
+type MerkleTree = BridgeTree<MerkleNode, { MERKLE_DEPTH }>;
+
+#[derive(Clone, SerialEncodable, SerialDecodable)]
+pub struct DaoBulla(pub pallas::Base);
 
 #[repr(u8)]
 pub enum DaoFunction {
@@ -16,10 +25,23 @@ pub enum DaoFunction {
     Mint = 0x01,
 }
 
+impl From<u8> for DaoFunction {
+    fn from(b: u8) -> Self {
+        match b {
+            0x00 => Self::Foo,
+            0x01 => Self::Mint,
+            _ => panic!("Invalid function ID: {:#04x?}", b),
+        }
+    }
+}
+
 #[derive(SerialEncodable, SerialDecodable)]
 pub struct DaoMintParams {
-    pub a: u32,
-    pub b: u32
+    pub dao_bulla: DaoBulla,
+}
+#[derive(SerialEncodable, SerialDecodable)]
+pub struct DaoMintUpdate {
+    pub dao_bulla: DaoBulla,
 }
 
 define_contract!(
@@ -30,7 +52,11 @@ define_contract!(
 );
 
 fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
-    let db_handle = db_init(cid, "wagies")?;
+    let db_handle = db_init(cid, "info")?;
+
+    let dao_tree = MerkleTree::new(100);
+    let dao_tree_data = serialize(&dao_tree);
+    db_set(db_handle, &serialize(&"dao_tree".to_string()), &dao_tree_data)?;
 
     Ok(())
 }
@@ -46,10 +72,47 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
     Ok(())
 }
 fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
+    let (call_idx, call): (u32, Vec<ContractCall>) = deserialize(ix)?;
+
+    assert!(call_idx < call.len() as u32);
+    let self_ = &call[call_idx as usize];
+
+    match DaoFunction::from(self_.data[0]) {
+        DaoFunction::Mint => {
+            let data = &self_.data[1..];
+            let params: DaoMintParams = deserialize(data)?;
+
+            // No checks in Mint. Just return the update.
+
+            let update = DaoMintUpdate { dao_bulla: params.dao_bulla };
+
+            let mut update_data = Vec::new();
+            update_data.write_u8(DaoFunction::Mint as u8);
+            update.encode(&mut update_data);
+            set_return_data(&update_data)?;
+            msg!("update is set!");
+        }
+        DaoFunction::Foo => {
+            unimplemented!();
+        }
+    }
+
     Ok(())
 }
 fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
-    let db_handle = db_lookup(cid, "wagies")?;
-    db_set(db_handle, &serialize(&"jason_gulag".to_string()), &serialize(&110))?;
+    match DaoFunction::from(update_data[0]) {
+        DaoFunction::Mint => {
+            let data = &update_data[1..];
+            let update: DaoMintUpdate = deserialize(data)?;
+
+            let db_handle = db_lookup(cid, "info")?;
+            let node = MerkleNode::new(update.dao_bulla.0);
+            merkle_add(db_handle, &serialize(&"dao_tree".to_string()), &node)?;
+        }
+        DaoFunction::Foo => {
+            unimplemented!();
+        }
+    }
+
     Ok(())
 }

+ 52 - 3
example/dao2/contract/money/src/lib.rs

@@ -1,8 +1,57 @@
+use darkfi_sdk::{
+    crypto::ContractId,
+    db::{db_get, db_init, db_lookup, db_set},
+    define_contract,
+    error::ContractResult,
+    msg,
+    pasta::pallas,
+    tx::ContractCall,
+    util::{get_object_bytes, get_object_size, put_object_bytes, set_return_data},
+};
+use darkfi_serial::{
+    deserialize, serialize, Encodable, ReadExt, SerialDecodable, SerialEncodable, WriteExt,
+};
+
 #[repr(u8)]
 pub enum MoneyFunction {
-    Bar = 0x01,
+    Foo = 0x00,
+    Mint = 0x01,
+}
+
+#[derive(SerialEncodable, SerialDecodable)]
+pub struct MoneyMintParams {
+    pub a: u32,
+    pub b: u32,
+}
+
+define_contract!(
+    init: init_contract,
+    exec: process_instruction,
+    apply: process_update,
+    metadata: get_metadata
+);
+
+fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
+    let db_handle = db_init(cid, "wagies")?;
+
+    Ok(())
 }
+fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
+    let zk_public_values: Vec<(String, Vec<pallas::Base>)> = Vec::new();
+    let signature_public_keys: Vec<pallas::Point> = Vec::new();
+
+    let mut metadata = Vec::new();
+    zk_public_values.encode(&mut metadata)?;
+    signature_public_keys.encode(&mut metadata)?;
+    set_return_data(&metadata)?;
 
-pub fn bar() {
-    println!("bar");
+    Ok(())
+}
+fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
+    Ok(())
+}
+fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
+    let db_handle = db_lookup(cid, "wagies")?;
+    db_set(db_handle, &serialize(&"jason_gulag".to_string()), &serialize(&110))?;
+    Ok(())
 }

+ 264 - 5
example/dao2/src/main.rs

@@ -1,22 +1,69 @@
 use darkfi::{
     blockchain::Blockchain,
     consensus::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
+    crypto::{
+        coin::Coin,
+        keypair::{Keypair, PublicKey, SecretKey},
+        proof::{ProvingKey, VerifyingKey},
+        types::{DrkSpendHook, DrkUserData, DrkValue},
+        util::{pedersen_commitment_u64, poseidon_hash},
+    },
     runtime::vm_runtime::Runtime,
+    zk::circuit::{BurnContract, MintContract},
+    zkas::decoder::ZkBinary,
     Result,
 };
-use darkfi_sdk::{crypto::ContractId, pasta::pallas, tx::ContractCall};
-use darkfi_serial::{serialize, deserialize, Decodable, Encodable, WriteExt};
-use std::io::Cursor;
+use darkfi_sdk::{
+    crypto::{constants::MERKLE_DEPTH, ContractId, MerkleNode},
+    tx::ContractCall,
+};
+use darkfi_serial::{deserialize, serialize, Decodable, Encodable, WriteExt};
+use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
+use log::{debug, error};
+use pasta_curves::{
+    arithmetic::CurveAffine,
+    group::{ff::Field, Curve, Group},
+    pallas,
+};
+use rand::rngs::OsRng;
+use std::{
+    any::{Any, TypeId},
+    io::Cursor,
+    time::Instant,
+};
 
 use dao_contract::{DaoFunction, DaoMintParams};
 
+use crate::{
+    contract::{dao, example, money},
+    note::EncryptedNote2,
+    schema::WalletCache,
+    tx::Transaction,
+    util::{sign, StateRegistry, ZkContractTable},
+};
+
 mod contract;
 mod error;
 mod note;
 mod schema;
+mod tx;
 mod util;
 
 fn show_dao_state(chain: &Blockchain, contract_id: &ContractId) -> Result<()> {
+    let db = chain.contracts.lookup(&chain.sled_db, contract_id, "info")?;
+    match db.get(&serialize(&"dao_tree".to_string())).expect("dao_tree") {
+        Some(value) => {
+            debug!(target: "demo", "DAO tree: {} bytes", value.len());
+        }
+        None => {
+            error!(target: "demo", "Missing DAO tree");
+        }
+    }
+
+    Ok(())
+}
+
+fn show_money_state(chain: &Blockchain, contract_id: &ContractId) -> Result<()> {
     let db = chain.contracts.lookup(&chain.sled_db, contract_id, "wagies")?;
     for obj in db.iter() {
         let (key, value) = obj.unwrap();
@@ -43,19 +90,229 @@ async fn main() -> BoxResult<()> {
 
     println!("wakie wakie young wagie");
 
+    //return Ok(());
+
     //schema::schema().await?;
     //return Ok(());
 
     // =============================
-    // Initialize a dummy blockchain
+    // Setup initial program parameters
     // =============================
+
+    // Money parameters
+    let xdrk_supply = 1_000_000;
+    let xdrk_token_id = pallas::Base::random(&mut OsRng);
+
+    // Governance token parameters
+    let gdrk_supply = 1_000_000;
+    let gdrk_token_id = pallas::Base::random(&mut OsRng);
+
+    // DAO parameters
+    let dao_proposer_limit = 110;
+    let dao_quorum = 110;
+    let dao_approval_ratio_quot = 1;
+    let dao_approval_ratio_base = 2;
+
+    // Initialize ZK binary table
+    let mut zk_bins = ZkContractTable::new();
+
+    debug!(target: "demo", "Loading dao-mint.zk");
+    let zk_dao_mint_bincode = include_bytes!("../proof/dao-mint.zk.bin");
+    let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
+    zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
+
+    /*
+    debug!(target: "demo", "Loading money-transfer contracts");
+    {
+        let start = Instant::now();
+        let mint_pk = ProvingKey::build(11, &MintContract::default());
+        debug!("Mint PK: [{:?}]", start.elapsed());
+        let start = Instant::now();
+        let burn_pk = ProvingKey::build(11, &BurnContract::default());
+        debug!("Burn PK: [{:?}]", start.elapsed());
+        let start = Instant::now();
+        let mint_vk = VerifyingKey::build(11, &MintContract::default());
+        debug!("Mint VK: [{:?}]", start.elapsed());
+        let start = Instant::now();
+        let burn_vk = VerifyingKey::build(11, &BurnContract::default());
+        debug!("Burn VK: [{:?}]", start.elapsed());
+
+        zk_bins.add_native("money-transfer-mint".to_string(), mint_pk, mint_vk);
+        zk_bins.add_native("money-transfer-burn".to_string(), burn_pk, burn_vk);
+    }
+    debug!(target: "demo", "Loading dao-propose-main.zk");
+    let zk_dao_propose_main_bincode = include_bytes!("../proof/dao-propose-main.zk.bin");
+    let zk_dao_propose_main_bin = ZkBinary::decode(zk_dao_propose_main_bincode)?;
+    zk_bins.add_contract("dao-propose-main".to_string(), zk_dao_propose_main_bin, 13);
+    debug!(target: "demo", "Loading dao-propose-burn.zk");
+    let zk_dao_propose_burn_bincode = include_bytes!("../proof/dao-propose-burn.zk.bin");
+    let zk_dao_propose_burn_bin = ZkBinary::decode(zk_dao_propose_burn_bincode)?;
+    zk_bins.add_contract("dao-propose-burn".to_string(), zk_dao_propose_burn_bin, 13);
+    debug!(target: "demo", "Loading dao-vote-main.zk");
+    let zk_dao_vote_main_bincode = include_bytes!("../proof/dao-vote-main.zk.bin");
+    let zk_dao_vote_main_bin = ZkBinary::decode(zk_dao_vote_main_bincode)?;
+    zk_bins.add_contract("dao-vote-main".to_string(), zk_dao_vote_main_bin, 13);
+    debug!(target: "demo", "Loading dao-vote-burn.zk");
+    let zk_dao_vote_burn_bincode = include_bytes!("../proof/dao-vote-burn.zk.bin");
+    let zk_dao_vote_burn_bin = ZkBinary::decode(zk_dao_vote_burn_bincode)?;
+    zk_bins.add_contract("dao-vote-burn".to_string(), zk_dao_vote_burn_bin, 13);
+    let zk_dao_exec_bincode = include_bytes!("../proof/dao-exec.zk.bin");
+    let zk_dao_exec_bin = ZkBinary::decode(zk_dao_exec_bincode)?;
+    zk_bins.add_contract("dao-exec".to_string(), zk_dao_exec_bin, 13);
+
+    // State for money contracts
+    let cashier_signature_secret = SecretKey::random(&mut OsRng);
+    let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
+    let faucet_signature_secret = SecretKey::random(&mut OsRng);
+    let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
+    */
+
+    // We use this to receive coins
+    let mut cache = WalletCache::new();
+
+    // Initialize a dummy blockchain
     // TODO: This blockchain interface should perhaps be ValidatorState and Mutex/RwLock.
     let db = sled::Config::new().temporary(true).open()?;
     let blockchain = Blockchain::new(&db, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES)?;
 
     // ================================================================
-    // Load the wasm binary into memory and create an execution runtime
+    // Deploy the wasm contracts
     // ================================================================
+
+    let dao_wasm_bytes = std::fs::read("dao_contract.wasm")?;
+    let dao_contract_id = ContractId::from(pallas::Base::from(1));
+    let money_wasm_bytes = std::fs::read("money_contract.wasm")?;
+    let money_contract_id = ContractId::from(pallas::Base::from(2));
+
+    // Block 1
+    // This has 2 transaction deploying the DAO and Money wasm contracts
+    // together with their ZK proofs.
+    {
+        let mut dao_runtime = Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
+        let mut money_runtime =
+            Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
+
+        // 1. exec() - zk and sig verify also
+        // ... none in this block
+
+        // 2. commit() - all apply() and deploy()
+        // Deploy function to initialize the smart contract state.
+        // Here we pass an empty payload, but it's possible to feed in arbitrary data.
+        dao_runtime.deploy(&[])?;
+        money_runtime.deploy(&[])?;
+        debug!(target: "demo", "Deployed DAO and money contracts");
+    }
+
+    // ================================================================
+    // DAO::mint()
+    // ================================================================
+
+    // Wallet
+    let dao_keypair = Keypair::random(&mut OsRng);
+    let dao_bulla_blind = pallas::Base::random(&mut OsRng);
+    let tx = {
+        let signature_secret = SecretKey::random(&mut OsRng);
+        // Create DAO mint tx
+        let builder = dao::mint::wallet::Builder {
+            dao_proposer_limit,
+            dao_quorum,
+            dao_approval_ratio_quot,
+            dao_approval_ratio_base,
+            gov_token_id: gdrk_token_id,
+            dao_pubkey: dao_keypair.public,
+            dao_bulla_blind,
+            signature_secret,
+        };
+        let (params, dao_mint_proofs) = builder.build(&zk_bins);
+
+        // Write the actual call data
+        let mut calldata = Vec::new();
+        // Selects which path executes in the contract.
+        calldata.write_u8(DaoFunction::Mint as u8)?;
+        params.encode(&mut calldata)?;
+
+        let calls = vec![ContractCall { contract_id: dao_contract_id, data: calldata }];
+
+        //let mut payload = Vec::new();
+        ////// Write the actual payload data
+        //let call_index = 0;
+        //payload.write_u32(call_index)?;
+        //func_calls.encode(&mut payload)?;
+
+        let signatures = vec![];
+        //for func_call in &func_calls {
+        //    let sign = sign([signature_secret].to_vec(), func_call);
+        //    signatures.push(sign);
+        //}
+
+        //let tx = Transaction { func_calls, signatures };
+        let proofs = vec![dao_mint_proofs];
+
+        Transaction { calls, proofs, signatures }
+    };
+
+    //// Validator
+
+    // We can do all exec(), zk proof checks and signature verifies in parallel.
+    let mut updates = vec![];
+    // Validate all function calls in the tx
+    for (idx, call) in tx.calls.iter().enumerate() {
+        // So then the verifier will lookup the corresponding state_transition and apply
+        // functions based off the func_id
+
+        // Write the actual payload data
+        let mut payload = Vec::new();
+        // Call index
+        payload.write_u32(idx as u32)?;
+        // Actuall calldata
+        tx.calls.encode(&mut payload)?;
+
+        match call.contract_id {
+            dao_contract_id => {
+                debug!(target: "demo", "DAO::exec() contract called");
+                let mut runtime =
+                    Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
+                let update = runtime.exec(&payload)?;
+                updates.push(update);
+            }
+            money_contract_id => {
+                debug!(target: "demo", "Money::exec() contract called");
+                let mut runtime =
+                    Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
+                let update = runtime.exec(&payload)?;
+                updates.push(update);
+            }
+            _ => {}
+        }
+    }
+
+    //tx.zk_verify(&zk_bins).unwrap();
+    //tx.verify_sigs();
+
+    // Now we finished verification stage, just apply all changes
+    assert_eq!(tx.calls.len(), updates.len());
+    for (call, update) in tx.calls.iter().zip(updates.iter()) {
+        match call.contract_id {
+            dao_contract_id => {
+                debug!(target: "demo", "DAO::apply() contract called");
+                let mut runtime =
+                    Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
+                runtime.apply(&update)?;
+            }
+            money_contract_id => {
+                debug!(target: "demo", "Money::apply() contract called");
+                let mut runtime =
+                    Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
+                runtime.apply(&update)?;
+            }
+            _ => {}
+        }
+    }
+
+    /////////////////////////////////////////////////
+    // Old stuff
+    /////////////////////////////////////////////////
+    /*
     let wasm_bytes = std::fs::read("dao_contract.wasm")?;
     let dao_contract_id = ContractId::from(pallas::Base::from(1));
     let mut runtime = Runtime::new(&wasm_bytes, blockchain.clone(), dao_contract_id)?;
@@ -105,8 +362,10 @@ async fn main() -> BoxResult<()> {
     let mut decoder = Cursor::new(&metadata);
     let zk_public_values: Vec<(String, Vec<pallas::Base>)> = Decodable::decode(&mut decoder)?;
     let signature_public_keys: Vec<pallas::Point> = Decodable::decode(decoder)?;
+    */
 
     show_dao_state(&blockchain, &dao_contract_id)?;
+    show_money_state(&blockchain, &money_contract_id)?;
 
     Ok(())
 }

+ 2 - 1
example/dao2/src/schema.rs

@@ -174,6 +174,7 @@ pub async fn example() -> Result<()> {
 }
 
 pub async fn schema() -> Result<()> {
+    /*
     // Example smart contract
     //// TODO: this will be moved to a different file
     example().await?;
@@ -1288,7 +1289,7 @@ pub async fn schema() -> Result<()> {
     tx.verify_sigs();
 
     //// Wallet
+    */
 
     Ok(())
 }
-

+ 1 - 1
src/runtime/import/db.rs

@@ -29,7 +29,7 @@ use crate::{
 
 /// Internal wasm runtime API for sled trees
 pub struct DbHandle {
-    contract_id: ContractId,
+    pub contract_id: ContractId,
     tree: sled::Tree,
 }
 

+ 3 - 0
src/runtime/import/mod.rs

@@ -19,5 +19,8 @@
 /// Host functions for interacting with db backend
 pub(crate) mod db;
 
+/// Host functions for merkle tree functions
+pub(crate) mod merkle;
+
 /// Host functions for utilities
 pub(crate) mod util;

+ 6 - 0
src/runtime/vm_runtime.rs

@@ -222,6 +222,12 @@ impl Runtime {
                     &ctx,
                     import::util::get_object_size,
                 ),
+
+                "merkle_add_" => Function::new_typed_with_env(
+                    &mut store,
+                    &ctx,
+                    import::merkle::merkle_add,
+                ),
             }
         };
 

+ 4 - 0
src/sdk/src/crypto/merkle_node.rs

@@ -54,6 +54,10 @@ lazy_static! {
 pub struct MerkleNode(pallas::Base);
 
 impl MerkleNode {
+    pub fn new(v: pallas::Base) -> Self {
+        Self(v)
+    }
+
     /// Reference the raw inner base field element
     pub fn inner(&self) -> pallas::Base {
         self.0

+ 1 - 1
src/sdk/src/db.rs

@@ -6,7 +6,7 @@ use super::{
     util::{get_object_bytes, get_object_size},
 };
 
-type DbHandle = u32;
+pub type DbHandle = u32;
 type TxHandle = u32;
 
 /// Only deploy() can call this. Creates a new database instance for this contract.

+ 3 - 0
src/sdk/src/lib.rs

@@ -34,6 +34,9 @@ pub mod log;
 /// Crypto-related definitions
 pub mod crypto;
 
+/// Merkle
+pub mod merkle;
+
 /// Transaction structure
 pub mod tx;
 

+ 1 - 1
src/sdk/src/tx.rs

@@ -6,5 +6,5 @@ use super::crypto::ContractId;
 #[derive(SerialEncodable, SerialDecodable)]
 pub struct ContractCall {
     pub contract_id: ContractId,
-    pub calldata: Vec<u8>,
+    pub data: Vec<u8>,
 }

+ 15 - 14
src/serial/src/lib.rs

@@ -73,8 +73,6 @@ pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T, Error> {
 
 /// Extensions of `Write` to encode data as per Bitcoin consensus.
 pub trait WriteExt {
-    /// Output a platform-specific unsigned int (DANGEROUS AND UNDEFINED)
-    fn write_usize(&mut self, v: usize) -> Result<(), Error>;
     /// Output a 128-bit unsigned int
     fn write_u128(&mut self, v: u128) -> Result<(), Error>;
     /// Output a 64-bit unsigned int
@@ -86,8 +84,6 @@ pub trait WriteExt {
     /// Output an 8-bit unsigned int
     fn write_u8(&mut self, v: u8) -> Result<(), Error>;
 
-    /// Output a platform-specific signed int (DANGEROUS AND UNDEFINED)
-    fn write_isize(&mut self, v: isize) -> Result<(), Error>;
     /// Output a 128-bit signed int
     fn write_i128(&mut self, v: i128) -> Result<(), Error>;
     /// Output a 64-bit signed int
@@ -113,8 +109,6 @@ pub trait WriteExt {
 
 /// Extensions of `Read` to decode data as per Bitcoin consensus.
 pub trait ReadExt {
-    /// Read a platform-specific unsigned int (DANGEROUS AND UNDEFINED)
-    fn read_usize(&mut self) -> Result<usize, Error>;
     /// Read a 128-bit unsigned int
     fn read_u128(&mut self) -> Result<u128, Error>;
     /// Read a 64-bit unsigned int
@@ -126,8 +120,6 @@ pub trait ReadExt {
     /// Read an 8-bit unsigned int
     fn read_u8(&mut self) -> Result<u8, Error>;
 
-    /// Read a platform-specific signed int (DANGEROUS AND UNDEFINED)
-    fn read_isize(&mut self) -> Result<isize, Error>;
     /// Read a 128-bit signed int
     fn read_i128(&mut self) -> Result<i128, Error>;
     /// Read a 64-bit signed int
@@ -173,12 +165,10 @@ macro_rules! decoder_fn {
 }
 
 impl<W: Write> WriteExt for W {
-    encoder_fn!(write_usize, usize, usize_to_array_le);
     encoder_fn!(write_u128, u128, u128_to_array_le);
     encoder_fn!(write_u64, u64, u64_to_array_le);
     encoder_fn!(write_u32, u32, u32_to_array_le);
     encoder_fn!(write_u16, u16, u16_to_array_le);
-    encoder_fn!(write_isize, isize, isize_to_array_le);
     encoder_fn!(write_i128, i128, i128_to_array_le);
     encoder_fn!(write_i64, i64, i64_to_array_le);
     encoder_fn!(write_i32, i32, i32_to_array_le);
@@ -205,12 +195,10 @@ impl<W: Write> WriteExt for W {
 }
 
 impl<R: Read> ReadExt for R {
-    decoder_fn!(read_usize, usize, slice_to_usize_le, usize::BITS as usize / 8);
     decoder_fn!(read_u128, u128, slice_to_u128_le, 16);
     decoder_fn!(read_u64, u64, slice_to_u64_le, 8);
     decoder_fn!(read_u32, u32, slice_to_u32_le, 4);
     decoder_fn!(read_u16, u16, slice_to_u16_le, 2);
-    decoder_fn!(read_isize, isize, slice_to_isize_le, isize::BITS as usize / 8);
     decoder_fn!(read_i128, i128, slice_to_i128_le, 16);
     decoder_fn!(read_i64, i64, slice_to_i64_le, 8);
     decoder_fn!(read_i32, i32, slice_to_i32_le, 4);
@@ -264,14 +252,12 @@ impl_int_encodable!(u16, read_u16, write_u16);
 impl_int_encodable!(u32, read_u32, write_u32);
 impl_int_encodable!(u64, read_u64, write_u64);
 impl_int_encodable!(u128, read_u128, write_u128);
-impl_int_encodable!(usize, read_usize, write_usize);
 
 impl_int_encodable!(i8, read_i8, write_i8);
 impl_int_encodable!(i16, read_i16, write_i16);
 impl_int_encodable!(i32, read_i32, write_i32);
 impl_int_encodable!(i64, read_i64, write_i64);
 impl_int_encodable!(i128, read_i128, write_i128);
-impl_int_encodable!(isize, read_isize, write_isize);
 
 /// Variable-integer encoding
 #[derive(Debug, PartialEq, Eq)]
@@ -397,6 +383,21 @@ macro_rules! encode_payload {
 }
 
 // Implementations for some primitive types.
+impl Encodable for usize {
+    #[inline]
+    fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize, Error> {
+        s.write_u64(*self as u64)?;
+        Ok(8)
+    }
+}
+
+impl Decodable for usize {
+    #[inline]
+    fn decode<D: Read>(mut d: D) -> Result<Self, Error> {
+        Ok(ReadExt::read_u64(&mut d)? as usize)
+    }
+}
+
 impl Encodable for f64 {
     #[inline]
     fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize, Error> {