Browse Source

hoonc improvements, wallet master pubkey export and import, readme improvements

tacryt-socryp 6 months ago
parent
commit
168606a3cd

+ 2 - 2
.env_example

@@ -1,3 +1,3 @@
-RUST_LOG=info,nockchain=debug,nockchain_libp2p_io=info,libp2p=info,libp2p_quic=info
+RUST_LOG=info,nockchain=info,nockchain_libp2p_io=info,libp2p=info,libp2p_quic=info
 MINIMAL_LOG_FORMAT=true
-MINING_PUBKEY=EHmKL2U3vXfS5GYAY5aVnGdukfDWwvkQPCZXnjvZVShsSQi3UAuA4tQQpVwGJMzc9FfpTY8pLDkqhBGfWutiF4prrCktUH9oAWJxkXQBzAavKDc95NR3DjmYwnnw8GuugnK
+MINING_PUBKEY=EHmKL2U3vXfS5GYAY5aVnGdukfDWwvkQPCZXnjvZVShsSQi3UAuA4tQQpVwGJMzc9FfpTY8pLDkqhBGfWutiF4prrCktUH9oAWJxkXQBzAavKDc95NR3DjmYwnnw8GuugnK

+ 0 - 3
Cargo.toml

@@ -27,9 +27,6 @@ path = "crates/hoonc"
 [workspace.dependencies.nockapp]
 path = "crates/nockapp"
 
-[workspace.dependencies.assert_no_alloc]
-path = "crates/nockvm/rust/assert_no_alloc"
-
 [workspace.dependencies.ibig]
 path = "crates/nockvm/rust/ibig"
 

+ 2 - 2
Makefile

@@ -3,7 +3,7 @@ include .env
 
 # Set default env variables if not set in .env
 export RUST_BACKTRACE ?= full
-export RUST_LOG ?= info,nockchain=debug,nockchain_libp2p_io=info,libp2p=info,libp2p_quic=info
+export RUST_LOG ?= info,nockchain=info,nockchain_libp2p_io=info,libp2p=info,libp2p_quic=info
 export MINIMAL_LOG_FORMAT ?= true
 export MINING_PUBKEY ?= 2qwq9dQRZfpFx8BDicghpMRnYGKZsZGxxhh9m362pzpM9aeo276pR1yHZPS41y3CW3vPKxeYM8p8fzZS8GXmDGzmNNCnVNekjrSYogqfEFMqwhHh5iCjaKPaDTwhupWqiXj6
 export
@@ -86,7 +86,7 @@ build-hoon: ensure-dirs update-hoonc $(HOON_TARGETS)
 .PHONY: run-nockchain
 run-nockchain:  # Run a nockchain node in follower mode with a mining pubkey
 	$(call show_env_vars)
-	mkdir -p miner-node && cd miner-node && rm -f nockchain.sock && RUST_BACKTRACE=1 cargo run --release --bin nockchain -- --npc-socket nockchain.sock --mining-pubkey $(MINING_PUBKEY) --bind /ip4/0.0.0.0/udp/3006/quic-v1 --mine
+	mkdir -p miner-node && cd miner-node && rm -f nockchain.sock && RUST_BACKTRACE=1 cargo run --release --bin nockchain -- --npc-socket nockchain.sock --mining-pubkey $(MINING_PUBKEY) --mine
 
 HOON_SRCS := $(find hoon -type file -name '*.hoon')
 

+ 172 - 13
README.md

@@ -27,6 +27,7 @@ Install `hoonc`, the Hoon compiler:
 
 ```
 make install-hoonc
+export PATH="$HOME/.cargo/bin:$PATH"
 ```
 
 To build the Nockchain and the wallet binaries and their required assets:
@@ -41,6 +42,7 @@ After you've run the setup and build commands, install the wallet:
 
 ```
 make install-nockchain-wallet
+export PATH="$HOME/.cargo/bin:$PATH"
 ```
 
 See the nockchain-wallet [README](./crates/nockchain-wallet/README.md) for more information.
@@ -52,6 +54,7 @@ After you've run the setup and build commands, install Nockchain:
 
 ```
 make install-nockchain
+export PATH="$HOME/.cargo/bin:$PATH"
 ```
 
 ## Setup Keys
@@ -88,23 +91,20 @@ nockchain-wallet import-keys --input keys.export
 
 ## Running Nodes
 
-To run a Nockchain miner:
+To run a Nockchain node without mining:
 
-```
-make run-nockchain
-```
+Make sure your current directory is nockchain.
 
-=======
-To run a Nockchain node without mining:
+To run a Nockchain node without mining.
 
 ```
-nockchain
+sh ./scripts/run_nockchain_node.sh
 ```
 
 To run a Nockchain node and mine to a pubkey:
 
 ```
-nockchain --mining-pubkey <your_pubkey> --mine
+sh ./scripts/run_nockchain_miner.sh
 ```
 
 For launch, make sure you run in a fresh working directory that does not include a .data.nockchain file from testing.
@@ -118,14 +118,173 @@ Yes, you can use the same pubkey if running multiple miners.
 
 ### How do I change the mining pubkey?
 
-Run `nockchain-wallet keygen` to generate a new key pair and copy the new public key to the `.env` file.
+Run `nockchain-wallet keygen` to generate a new key pair.
+
+If you are using the Makefile workflow, copy the public key to the `.env` file.
+
+### How do I run multiple instances on the same machine?
+
+To run multiple instances on the same machine, you need to:
+
+1. Create separate working directories for each instance
+2. Use different ports for each instance
 
-### How do I import an existing key that I generated with a different tool?
+Here's how to set it up:
 
-If you have a **base58 encoded** public key *AND* a **base58 encoded** chain code, you can import it with:
+```bash
+Inside of the nockchain directory:
 
+# Create directories for each instance
+mkdir node1 node2
+
+# Copy .env to each directory
+cp .env node1/
+cp .env node2/
+
+# Run each instance in its own directory with .env loaded
+cd node1 && sh ../scripts/run_nockchain_miner.sh
+cd node2 && sh ../scripts/run_nockchain_miner.sh
 ```
-nockchain-wallet import-master-pubkey --key <base58-encoded-public-key> --chain-code <base58-encoded-chain-code>
+
+### What are the networking requirements?
+
+Nockchain requires:
+
+1. Internet.
+2. If you are behind a firewall, you need to specify the p2p ports to use and open them..
+   - Example: `nockchain --bind /ip4/0.0.0.0/udp/$PEER_PORT/quic-v1`
+3. **NAT Configuration (if you are behind one)**:
+   - If behind NAT, configure port forwarding for the peer port
+   - Use `--bind` to specify your public IP/domain
+   - Example: `nockchain --bind /ip4/1.2.3.4/udp/$PEER_PORT/quic-v1`
+
+### Why aren't Zorp peers connecting?
+
+Common reasons for peer connection failures:
+
+1. **Network Issues**:
+   - Firewall blocking P2P port
+   - NAT not properly configured
+   - Incorrect bind address
+
+2. **Configuration Issues**:
+   - Invalid peer IDs
+
+3. **Debug Steps**:
+   - Check logs for connection errors
+   - Verify port forwarding
+
+### What do outgoing connection failures mean?
+
+Outgoing connection failures can occur due to:
+
+1. **Network Issues**:
+   - Peer is offline
+   - Firewall blocking connection
+   - NAT traversal failure
+
+2. **Peer Issues**:
+   - Peer has reached connection limit
+   - Peer is blocking your IP
+
+3. **Debug Steps**:
+   - Check peer's status
+   - Verify network connectivity
+   - Check logs for specific error messages
+
+### How do I know if it's mining?
+
+No way to manually check mining status yet. We're working on it.
+
+In the meantime, you can check the logs for mining activity.
+
+If you see a line that looks like:
+
+```sh
+[%mining-on 12.040.301.481.503.404.506 17.412.404.101.022.637.021 1.154.757.196.846.835.552 12.582.351.418.886.020.622 6.726.267.510.179.724.279]
 ```
 
-But you really should use the `nockchain-wallet keygen` command to generate a new key pair and use that instead.
+### How do I check block height?
+
+No way to manually check block height yet. We're working on it.
+
+In the meantime, you can check the logs for a line like:
+
+```sh
+block Vo3d2Qjy1YHMoaHJBeuQMgi4Dvi3Z2GrcHNxvNYAncgzwnQYLWnGVE added to validated blocks at 2
+```
+
+That last number is the block height.
+
+### What do common errors mean?
+
+Common errors and their solutions:
+
+1. **Connection Errors**:
+   - `Failed to dial peer`: Network connectivity issues, you may still be connected though.
+   - `Handshake with the remote timed out`: Peer might be offline, not a fatal issue.
+
+### How do I check wallet balance?
+
+To check your wallet balance:
+
+```bash
+# List all notes (UTXOs) that your node has seen
+nockchain-wallet --nockchain-socket ./nockchain.sock list-notes
+
+# List all notes by pubkey
+nockchain-wallet --nockchain-socket ./nockchain.sock list-notes-by-pubkey <your-pubkey>
+```
+
+### How do I configure logging levels?
+
+To reduce logging verbosity, you can set the `RUST_LOG` environment variable before running nockchain:
+
+```bash
+# Show only info and above
+RUST_LOG=info nockchain
+
+# Show only errors
+RUST_LOG=error nockchain
+
+# Show specific module logs (e.g. only p2p events)
+RUST_LOG=nockchain_libp2p_io=info nockchain
+
+# Multiple modules with different levels
+RUST_LOG=nockchain_libp2p_io=info,nockchain=warn nockchain
+```
+
+Common log levels from most to least verbose:
+- `trace`: Very detailed debugging information
+- `debug`: Debugging information
+- `info`: General operational information
+- `warn`: Warning messages
+- `error`: Error messages
+
+You can also add this to your `.env` file if you're running with the Makefile:
+```
+RUST_LOG=info
+```
+
+### Troubleshooting Common Issues
+
+1. **Node Won't Start**:
+   - Check port availability
+   - Verify .env configuration
+   - Check for existing .data.nockchain file
+   - Ensure proper permissions
+
+2. **No Peers Connecting**:
+   - Verify port forwarding
+   - Check firewall settings
+
+3. **Mining Not Working**:
+   - Verify mining pubkey
+   - Check --mine flag
+   - Ensure peers are connected
+   - Check system resources
+
+4. **Wallet Issues**:
+   - Verify key import/export
+   - Check socket connection
+   - Ensure proper permissions

+ 1 - 2
crates/hoonc/Cargo.toml

@@ -15,7 +15,7 @@ nockvm = { workspace = true }
 nockvm_macros = { workspace = true }
 tempfile = { workspace = true }
 thiserror = { workspace = true }
-tokio = { workspace = true }
+tokio = { workspace = true, features = ["sync"] }
 tracing = { workspace = true }
 tracing-subscriber = { workspace = true }
 # tracing-tracy = { workspace = true, features = ["flush-on-exit"] }
@@ -24,4 +24,3 @@ walkdir = "2.5.0"
 [[bin]]
 name = "hoonc"
 path = "src/main.rs"
-

+ 10 - 6
crates/hoonc/src/lib.rs

@@ -6,6 +6,8 @@ use clap::{arg, command, ColorChoice, Parser};
 use nockapp::driver::Operation;
 use nockapp::kernel::boot::{self, default_boot_cli, Cli as BootCli};
 use nockapp::noun::slab::NounSlab;
+use nockapp::one_punch::OnePunchWire;
+use nockapp::wire::Wire;
 use nockapp::{system_data_dir, AtomExt, Noun, NounExt};
 use nockvm::interpreter::{self, Context};
 use nockvm::noun::{Atom, D, T};
@@ -203,6 +205,9 @@ pub async fn initialize_hoonc_(
         Some(data_dir),
     )
     .await?;
+    nockapp.add_io_driver(nockapp::file_driver()).await;
+    nockapp.add_io_driver(nockapp::exit_driver()).await;
+
     let mut slab = NounSlab::new();
     let hoon_cord = Atom::from_value(&mut slab, HOON_TXT)
         .unwrap_or_else(|_| {
@@ -217,10 +222,9 @@ pub async fn initialize_hoonc_(
     let bootstrap_poke = T(&mut slab, &[D(tas!(b"boot")), hoon_cord]);
     slab.set_root(bootstrap_poke);
 
-    nockapp
-        .add_io_driver(nockapp::one_punch_driver(slab, Operation::Poke))
-        .await;
-
+    // It's OK to do a raw poke for boot because it doesn't yield any effects that need to be processed.
+    // We do a raw poke here to ensure boot is done before we start the build poke.
+    let _boot_result = nockapp.poke(OnePunchWire::Poke.to_wire(), slab).await?;
     let mut slab = NounSlab::new();
     let entry_contents = {
         let mut contents_vec: Vec<u8> = vec![];
@@ -296,11 +300,11 @@ pub async fn initialize_hoonc_(
         ],
     );
     slab.set_root(poke);
+    // The build poke yields effects (principally the file write effect), so we need to embed the poke
+    // as a one_punch IO driver so that nockapp.run() can process the effects.
     nockapp
         .add_io_driver(nockapp::one_punch_driver(slab, Operation::Poke))
         .await;
-    nockapp.add_io_driver(nockapp::file_driver()).await;
-    nockapp.add_io_driver(nockapp::exit_driver()).await;
     Ok((nockapp, out_path_string.into()))
 }
 

+ 23 - 0
crates/nockapp/src/nockapp/mod.rs

@@ -217,8 +217,31 @@ impl NockApp {
         });
         // TODO: Stop using the task tracker for user code?
         self.tasks.spawn(fut);
+        debug!("Added IO driver");
+    }
 
+    /// Assume at-least-once processing and track the state necessary to know whether
+    /// all critical IO actions have been performed correctly or not from the jammed state.
+    #[tracing::instrument(skip(self, driver))]
+    pub async fn add_io_driver_(
+        &mut self,
+        driver: IODriverFn,
+    ) -> tokio::sync::mpsc::Sender<IOAction> {
+        let io_sender = self.action_channel_sender.clone();
+        let effect_sender = self.effect_broadcast.clone();
+        let effect_receiver = Mutex::new(self.effect_broadcast.subscribe());
+        let exit = self.exit.clone();
+        let fut = driver(NockAppHandle {
+            io_sender,
+            effect_sender,
+            effect_receiver,
+            exit,
+        });
+        // TODO: Stop using the task tracker for user code?
+        self.tasks.spawn(fut);
+        let io_sender = self.action_channel_sender.clone();
         debug!("Added IO driver");
+        io_sender
     }
 
     /// Purely for testing purposes (injecting delays) for now.

+ 28 - 12
crates/nockchain-wallet/src/main.rs

@@ -170,14 +170,14 @@ pub enum Commands {
     /// Update the wallet balance
     UpdateBalance,
 
+    /// Export a master public key
+    ExportMasterPubkey,
+
     /// Import a master public key
     ImportMasterPubkey {
-        /// Base58-encoded public key
-        #[arg(short, long)]
-        key: String,
-        /// Base58-encoded chain code
+        // Path to keys file generated from export-master-pubkey
         #[arg(short, long)]
-        chain_code: String,
+        key_path: String,
     },
 
     /// Lists all public keys in the wallet
@@ -209,6 +209,7 @@ impl Commands {
             Commands::SimpleSpend { .. } => "simple-spend",
             Commands::MakeTx { .. } => "make-tx",
             Commands::UpdateBalance => "update-balance",
+            Commands::ExportMasterPubkey => "export-master-pubkey",
             Commands::ImportMasterPubkey { .. } => "import-master-pubkey",
             Commands::ListPubkeys => "list-pubkeys",
             Commands::ShowSeedphrase => "show-seedphrase",
@@ -647,20 +648,35 @@ impl Wallet {
         Self::wallet("list-notes", &[], Operation::Poke, &mut slab)
     }
 
+    /// Exports the master public key.
+    ///
+    /// # Returns
+    ///
+    /// Retrieves and displays master public key and chaincode.
+    fn export_master_pubkey() -> CommandNoun<NounSlab> {
+        let mut slab = NounSlab::new();
+        Self::wallet("export-master-pubkey", &[], Operation::Poke, &mut slab)
+    }
+
     /// Imports a master public key.
     ///
     /// # Arguments
     ///
     /// * `key` - Base58-encoded public key
     /// * `chain_code` - Base58-encoded chain code
-    fn import_master_pubkey(key: &str, chain_code: &str) -> CommandNoun<NounSlab> {
+    fn import_master_pubkey(input_path: &str) -> CommandNoun<NounSlab> {
         let mut slab = NounSlab::new();
-        let key_noun = make_tas(&mut slab, key).as_noun();
-        let chain_code_noun = make_tas(&mut slab, chain_code).as_noun();
+
+        let key_data = fs::read(input_path)
+            .map_err(|e| CrownError::Unknown(format!("Failed to read master pubkeys: {}", e)))?;
+
+        let pubkey_noun = slab
+            .cue_into(key_data.as_bytes()?)
+            .map_err(|e| CrownError::Unknown(format!("Failed to decode master pubkeys: {}", e)))?;
 
         Self::wallet(
             "import-master-pubkey",
-            &[key_noun, chain_code_noun],
+            &[pubkey_noun],
             Operation::Poke,
             &mut slab,
         )
@@ -764,6 +780,7 @@ async fn main() -> Result<(), NockAppError> {
         | Commands::MakeTx { .. }
         | Commands::GenMasterPrivkey { .. }
         | Commands::GenMasterPubkey { .. }
+        | Commands::ExportMasterPubkey
         | Commands::ImportMasterPubkey { .. }
         | Commands::ListPubkeys
         | Commands::ShowSeedphrase
@@ -835,9 +852,8 @@ async fn main() -> Result<(), NockAppError> {
         } => Wallet::simple_spend(names.clone(), recipients.clone(), gifts.clone(), *fee),
         Commands::MakeTx { draft } => Wallet::make_tx(draft),
         Commands::UpdateBalance => Wallet::update_balance(),
-        Commands::ImportMasterPubkey { key, chain_code } => {
-            Wallet::import_master_pubkey(key, chain_code)
-        }
+        Commands::ExportMasterPubkey => Wallet::export_master_pubkey(),
+        Commands::ImportMasterPubkey { key_path } => Wallet::import_master_pubkey(key_path),
         Commands::ListPubkeys => Wallet::list_pubkeys(),
         Commands::ShowSeedphrase => Wallet::show_seedphrase(),
         Commands::ShowMasterPubkey => Wallet::show_master_pubkey(),

+ 5 - 0
crates/nockchain/src/lib.rs

@@ -341,6 +341,11 @@ fn load_keypair(keypair_path: &Path, force_new: bool) -> Result<Keypair, Box<dyn
         let keypair_bytes = std::fs::read(keypair_path)?;
         let keypair = libp2p::identity::Keypair::from_protobuf_encoding(&keypair_bytes[..])?;
         let peer_id = keypair.public().to_peer_id();
+        let pubkey_path = keypair_path.with_extension(PEER_ID_FILE_EXTENSION);
+        if !pubkey_path.exists() {
+            info!("Writing pubkey to {pubkey_path:?}");
+            std::fs::write(pubkey_path, peer_id.to_base58())?;
+        }
         info!("Loaded identity as peer {peer_id}");
         Ok(keypair)
     } else {

+ 42 - 12
hoon/apps/wallet/wallet.hoon

@@ -15,8 +15,8 @@
 |%
 ::    $key: public or private key
 ::
-::  a public key is generated from a private key and +cc (chain code).
-::  pub contains the base58 encoded version of the cheetah curve point
+::   both private and public keys are in serialized cheetah point form
+::   they MUST be converted to base58 for export.
 ::
 +$  key
   $~  [%pub p=*@ux]
@@ -160,7 +160,8 @@
       [%derive-child key-type=?(%pub %prv) i=@ label=(unit @t)]
       [%import-keys keys=(list (pair trek meta))]
       [%export-keys ~]
-      [%import-master-pubkey key=@t cc=@t]           ::  base58-encoded pubkey + chain code
+      [%export-master-pubkey ~]
+      [%import-master-pubkey =coil]                    ::  base58-encoded pubkey + chain code
       [%make-tx dat=draft]
       [%list-notes-by-pubkey pubkey=@t]                ::  base58-encoded pubkey
       $:  %simple-spend
@@ -1026,6 +1027,7 @@
       %update-block          (do-update-block cause)
       %import-keys           (do-import-keys cause)
       %export-keys           (do-export-keys cause)
+      %export-master-pubkey  (do-export-master-pubkey cause)
       %import-master-pubkey  (do-import-master-pubkey cause)
       %gen-master-privkey    (do-gen-master-privkey cause)
       %gen-master-pubkey     (do-gen-master-pubkey cause)
@@ -1310,24 +1312,52 @@
         [%exit 0]
     ==
   ::
+  ++  do-export-master-pubkey
+    |=  =cause
+    ?>  ?=(%export-master-pubkey -.cause)
+    %-  (debug "import-master-pubkey")
+    ?~  master.state
+      ~&  "wallet warning: no master keys available for export"
+      [[%exit 0]~ state]
+    =/  master-coil=coil  ~(master get:v %pub)
+    ?.  ?=(%pub -.key.master-coil)
+      ~&  "wallet fatal: master pubkey malformed"
+      [[%exit 0]~ state]
+    =/  dat-jam=@  (jam master-coil)
+    =/  key-b58=tape  (en:base58:wrap p.key.master-coil)
+    =/  cc-b58=tape  (en:base58:wrap cc.master-coil)
+    :_  state
+    :~  :-  %markdown
+        %-  crip
+        """
+        ## exported master public key:
+
+        - pubkey: {key-b58}
+        - chaincode: {cc-b58}
+
+        """
+        [%exit 0]
+        [%file %write 'master-pubkey.export' dat-jam]
+    ==
+  ::
   ++  do-import-master-pubkey
     |=  =cause
     ?>  ?=(%import-master-pubkey -.cause)
-    %-  (debug "import-master-pubkey: {<key.cause>}")
-    =/  c=coil  [%coil [%pub (de:base58:wrap (trip key.cause))] (de:base58:wrap (trip cc.cause))]
-    =/  cor  (from-public:s10 [p.key.c cc.c])
-    =/  master-pubkey-coil=coil  [%coil [%pub public-key] chain-code]:cor
+    %-  (debug "import-master-pubkey: {<coil.cause>}")
+    =/  master-pubkey-coil=coil  coil.cause
     =.  master.state  (some master-pubkey-coil)
-    =/  label  `(crip "master-public-{<(end [3 4] public-key:cor)>}")
-    %-  (debug "Imported master public key: {<public-key:cor>}")
+    =/  label  `(crip "master-public-{<(end [3 4] p.key.master-pubkey-coil)>}")
     =.  keys.state  (key:put:v master-pubkey-coil ~ label)
+    =/  key-b58=tape  (en:base58:wrap p.key.master-pubkey-coil)
+    =/  cc-b58=tape  (en:base58:wrap cc.master-pubkey-coil)
     :_  state
     :~  :-  %markdown
         %-  crip
         """
-        ## master public key
+        ## imported master public key:
 
-        {<public-key:cor>}
+            - pubkey: {key-b58}
+            - chaincode: {cc-b58}
         """
         [%exit 0]
     ==
@@ -1444,7 +1474,7 @@
         """
         ## master public key
 
-        {(en:base58:wrap p.key.meta)}
+          {(en:base58:wrap p.key.meta)}
         """
         [%exit 0]
     ==

+ 0 - 3
hoon/common/slip10.hoon

@@ -76,9 +76,6 @@
   |=  keyc
   +>(prv key, pub (point key a-gen:curve), cad cai)
 ::
-::  TODO: why is the input base58 encoded? will it be?
-::  TODO: assert that key is in G
-::  pt is not inf (id), if you raise it by G-order it should give you inf
 ++  from-public
   |=  keyc
   +>(pub (de-a-pt key), cad cai)

+ 0 - 5
hoon/common/ztd/eight.hoon

@@ -935,11 +935,6 @@
 ::
 ::  This is a dummy arm which is only here so lib/stark/prover.hoon can use it as its parent core.
 ::  Without it, jets won't work in that file.
-::
-::  !!!!!!!
-::  DONT RELEASE THIS IN THE OPEN SOURCE VERSION
-::  IT IS ALPHA FOR HOW TO GET JETS TO WORK
-::  !!!!!!!
 ++  stark-engine-jet-hook
   ~/  %stark-engine-jet-hook
   |=  n=@

+ 7 - 0
scripts/run_nockchain_miner.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+source .env
+export RUST_LOG
+export MINIMAL_LOG_FORMAT
+export MINING_PUBKEY
+nockchain --mining-pubkey ${MINING_PUBKEY} --mine
+

+ 6 - 0
scripts/run_nockchain_node.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+source .env
+export RUST_LOG
+export MINIMAL_LOG_FORMAT
+nockchain
+