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.