Quick Update on kiln: Bitcoin 'simnet' experimentation

Writing now from the beautiful Spanish coast, another vacation means more free time for kiln experimentation! Though truthfully, I'm mostly catching up on blogging to document some progress and some challenges from a couple weeks ago.

In previous posts, I discussed some challenges simulating the Bitcoin network for testing purposes. To recap, the problem is that mining Bitcoin is a fierce competition, but in a test environment, it's difficult to recreate the massive hashing race that makes the real Bitcoin network so powerful, secure, and consistent. I don't necessarily need security in a test environment, so a low hash rate on my local network is not an issue. But there is one problem created by lack of competition in my own little Bitcoin world running on my laptop: it's too easy. If I let a node start mining, it will mine blocks at a ridiculous pace. A bit faster than usual is okay, but several blocks per second is not realistic and does not support Lightning Network experimentation very well. In my observation, it's all a Lightning node can do to just keep up with blockchain synchronization if blocks are produced too fast, so there's no time to perform the basics like channel opens and closes.

To address this problem, I speculated that I could limit CPU allocated to my mining Bitcoin node. To accomplish this, I needed to implement a very standard practice for Kubernetes operators: configurable resource requests and especially limits. That part was quite simple to implement, but the results were not quite as fruitful as a imagined. Once I trained to kiln operator to limit CPU allocation to Bitcoin nodes based on BitcoinNode resource configuration, my first test set CPU allocation to 100 millicores (this is supposed to represent 10% of a single CPU core). This did not perceivably slow down block production. Next, I tried 50 millicores, then 10, then 1 (lol). No setting was low enough to add significant time to the production of a block.

Interestingly, I did notice that a 1 millicore limit did not seem to have a different impact than a 10 millicore limit. Either way, the mining node pod that I configured seemed to consume 10 millicores. I'm not sure at this point whether that's a Kubernetes resource management thing (a millicore is actually not a realistic unit of CPU to manage), or a limitation of my hardware, or a limitation of btcd, but regardless, I can't quite get a node to consume less than 10 millicores.

So the question remains, how can I slow down block production in my simnet environment? Perhaps I'll need to artificially raise the difficulty in my simulated environment. I'm not sure how I would approach this, perhaps I would need to start with a pre-canned blockchain state (instead of starting from block zero). At this point, I think it might be best for me to find some folks with experience and pick their brains.

If you'd like to try out the kiln operator and mine some blocks on the simnet with btcd, I've also just merged a very simple (to be enhanced later) Bitcoin node peer configuration capability. Here is the script I use to build, package, publish, and deploy:

export repo=kiln-fired
docker login quay.io/$repo

make docker-build IMG=quay.io/$repo/kiln-operator:latest
make docker-push IMG=quay.io/$repo/kiln-operator:latest

make manifests
make bundle IMG=quay.io/$repo/kiln-operator:latest
make bundle-build BUNDLE_IMG=quay.io/$repo/kiln-operator-bundle:latest
docker push quay.io/$repo/kiln-operator-bundle:latest

oc delete BitcoinNode,pvc --all -n kiln-test
operator-sdk cleanup kiln-operator -n kiln-operator
operator-sdk run bundle --install-mode AllNamespaces -n kiln-operator quay.io/$repo/kiln-operator-bundle:latest

You will want to set up your own image repository if you want to experiment with your own iterations on the code. Otherwise, you can skip to the last section and use the images I've already published.

The following are two Bitcoin node sample resources that will result in a mining scenario.

Here is the node that is meant to do the mining:

apiVersion: bitcoin.kiln-fired.github.io/v1alpha1
kind: BitcoinNode
metadata:
  name: btcd-a
spec:
  miningAddress: rhLmdkndRELHhHAUnSut5PhFZ8do8aNMk4
  miningEnabled: true
  resources:
    limits:
      cpu: 1m
      memory: 50Mi
    requests:
      cpu: 1m
      memory: 50Mi
  rpcServer:
    certSecret: btcd-a-rpc-tls
    password: st4cks4ts
    user: node-user

And here is a peer (one peer is required for mining to begin):

apiVersion: bitcoin.kiln-fired.github.io/v1alpha1
kind: BitcoinNode
metadata:
  name: btcd-b
spec:
  peer: btcd-a.kiln-test.svc.cluster.local:18555
  resources:
    limits:
      cpu: 10m
      memory: 50Mi
    requests:
      cpu: 10m
      memory: 50Mi
  rpcServer:
    certSecret: btcd-b-rpc-tls
    password: st4cks4ts
    user: node-user

Lastly, in other news, a few weeks ago, I had a conversation with a friend at Lightning Labs who pointed me to lndinit. After a quick review, this implementation is a perfect fit for some reuse in kiln. I'm super excited to dig in more, and potentially solve some problems generating that mining address you can see in the first line of the mining node spec shown above, along with a private key. I'm thinking it might be cool to derive private keys from a k8s secret that contains a seed phrase. That may not be my final design, but I think it could be a cool target user experience.

comments powered by Disqus