Mixin Kernel: a UTXO ledger that reaches agreement through signed snapshots on a BFT-DAG
🚀 The Mixin-BFT-DAG network reference implementation.
At a glance
- What is it?
- Mixin Kernel is the reference implementation of the Mixin network, a distributed ledger for digital assets built from a UTXO state model, parallel per-node chains, a cross-referenced DAG and collective signatures. The README is unusually explicit about custody boundaries, port assignments and the price of joining the consensus set, which makes it one of the more legible blockchain implementations to read.
- Who is it for?
- Mixin Kernel fits an engineer who wants to read a working ledger implementation end to end, run a seven-node network on one machine, and understand snapshot certification and UTXO finalization without a production chain, and it does not fit an application that needs custodial deposits or external-chain withdrawals handled for it, since those depend on separate custody services.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A ledger built from four pieces rather than one
Mixin Kernel is described as a distributed ledger for digital assets that combines a UTXO state model, parallel per-node chains, a cross-referenced directed acyclic graph, and collective signatures for Byzantine-fault-tolerant consensus.
Four components is a lot to hold in your head, so it helps to see how the README orders them. Its data flow runs from signed transactions into a transaction cache, then into snapshot validation and collective signing, then into short rounds on each node chain, and finally into a cross-referenced BFT-DAG with durable UTXO state.
signed transactions
↓
transaction cache
↓
snapshot validation + collective signing
↓
short rounds on each node chain
↓
cross-referenced BFT-DAG + durable UTXO stateThe parallel per-node chains are the unusual part. A node keeps its own short chain rather than appending to one global log, and the DAG is what cross-references those chains so that a consensus order can be derived. The UTXO model is the familiar one: value lives in unspent outputs, and a transaction consumes earlier outputs and creates new ones.
For the audience this matters most, the project is the reference implementation of the Mixin network, and the homepage link in the repository points at the Mixin Draft, a design document rather than a marketing page. The README also points to a technical paper in the repository for the data model, consensus, networking, storage and recovery paths. This is a codebase written to be read.
Snapshots are the unit of agreement, and they are capped
The consensus story is described in a few sentences. Accepted nodes propose snapshots concurrently. Post-genesis snapshot certification requires a supermajority under the protocol's membership rules. A snapshot can contain up to 255 eligible transactions, and each transaction retains its own payload hash, authorization rules and finalization record.
Three details deserve attention.
The concurrency is the point. Nodes do not take turns; they propose at the same time and the DAG plus collective signing sorts out an order. The supermajority requirement means a snapshot is not certified by one signer or even by a simple majority of signers, but by the membership rules the protocol defines, which is what makes the result Byzantine-fault-tolerant rather than merely fault-tolerant.
The 255 transaction limit is a hard ceiling on how much work one snapshot can certify. A busy node produces many small snapshots rather than occasional large ones. That has a visible consequence at the API level: the finalization of a given transaction is recorded per snapshot, so a transaction is not final until the snapshot that contains it is certified.
That same consequence shows up in the RPC documentation. A successful sendrawtransaction response alone does not establish finalization. The gettransaction method includes a snapshot field when the queried node records the transaction as finalized, and RPC results reflect the selected node's view. An application that releases external funds needs an appropriate finality check rather than a successful submission response.
Custody is deliberately outside the consensus rules
The README draws a line that most ledger documentation blurs. Asset deposits require custodian authorization. Checking external reserves and executing external-chain withdrawals depend on separate custody services.
That is a statement about responsibility, not an implementation detail. The ledger itself does not decide whether a depositor is allowed to put assets in, and it does not reach out to other chains to verify reserves or to move value out. Those operations belong to services that sit beside the kernel.
The consequence for anyone building on this code is architectural. A wallet that accepts a deposit has to integrate a custodian service for the authorization step, and an application promising cross-chain withdrawal has to integrate custody for execution and reserve checking. The kernel gives you the ledger semantics and the finalization record; it does not give you the bridge.
If your use case is a self-custodied ledger where every participant controls their own keys and no external asset ever crosses a boundary, this separation costs you nothing. If your use case is a gateway that ingests assets from other chains, you are assembling a second system, and the README is honest that the kernel is not that system.
Building with make, because plain go build produces a binary that will not start
The build section is short and has one trap in it. You install the Go version declared in go.mod, which is go 1.27.1, and then build with make. The Makefile embeds the Git commit identifier in the build version, and a binary built with plain go build refuses to start while the version contains BUILD_VERSION.
The Makefile itself is four lines of shell wrapped around a single build command:
all:
git checkout config/reader.go
sed -i -- "s/BUILD_VERSION/`git rev-parse --short HEAD`/g" config/reader.go || exit
CGO_ENABLED=0 go build -o mixin
git checkout config/reader.goThe mechanism is a substitution: the placeholder in config/reader.go is replaced with the short commit hash, the binary is compiled with CGO disabled, and the source file is restored from Git afterwards. The README asks for make to be run from a clean checkout, precisely because the Makefile rewrites a tracked file twice.
So the failure mode is specific. If you build with the go tool directly, you get a binary that starts, discovers that its version string still says BUILD_VERSION, and refuses to run. That looks like a broken build rather than a missing step, and the README warns about it in advance.
The documented sequence is:
git clone https://github.com/MixinNetwork/mixin.git
cd mixin
make
./mixin --versionThe resulting binary runs a Kernel node and provides tools for addresses, transactions, graph inspection and RPC access, with the full command reference behind ./mixin --help.
A seven node local network you can start in one command
The README documents a local test network that is unusually complete for a blockchain project, and it is the fastest way to see the consensus path work.
The setuptestnet command generates configuration for a seven-node test network under /tmp/mixin-6861 through /tmp/mixin-6867. It prints the generated genesis document, the network identifier and the test custodian credentials, and those credentials authorize deposits on that test network, so the README says to store them if the network will be reused.
./mixin setuptestnetThe seven nodes then run as separate processes, each pointed at its own directory:
./mixin kernel --dir /tmp/mixin-6861
./mixin kernel --dir /tmp/mixin-6862
# Continue with /tmp/mixin-6863 through /tmp/mixin-6867.The generated nodes use P2P UDP ports 5851 to 5857 and RPC TCP ports 6861 to 6867. A node can be checked from another terminal with the client, or with a plain HTTP POST to the RPC endpoint:
./mixin --node http://127.0.0.1:6861 getinfoOne behaviour to know before you experiment. Each invocation of setuptestnet overwrites the configuration and genesis files in those directories but leaves database contents in place. The README's advice is to use clean directories for each independent local network, because otherwise you can end up with new genesis on top of old state.
A node directory is genesis.json, config.toml and runtime databases
A node data directory contains genesis.json, config.toml and the databases created at runtime. The repository ships a starting pair, and the README shows how to copy them into place.
mkdir -p "$HOME/mixin"
cp config/genesis.json "$HOME/mixin/genesis.json"
cp config/config.example.toml "$HOME/mixin/config.toml"The configuration review before the first start is the security-critical part, and the README lists it. Replace node.signer-key with the node signer's private spend key, and never use the example key on a real node. Choose unused P2P, RPC and optional profiling ports. Keep p2p.relayer = false on a consensus signer, and only set it to true on a public relay that is intentionally reachable from the network. Review the seed list and expose the P2P UDP port if the node must accept direct peer connections.
There is one line that deserves a second read because it is about exposure rather than configuration: RPC and profiling listen on all interfaces at their configured ports, so access has to be restricted at the host or network boundary, and dev.port = 0 disables profiling.
The daemon is then started against that directory, and with the example configuration RPC is reachable locally at http://127.0.0.1:6860, which is the endpoint the CLI uses by default. You override it with the global --node flag or the MIXIN_KERNEL_RPC environment variable.
./mixin kernel --dir "$HOME/mixin"The last piece is the one that decides whether a node counts for anything in consensus. Joining the consensus set also requires a 13,439 XIN pledge and the automated acceptance sequence, and acceptance must satisfy the seven-day pledge-to-accept timestamp limit. A finalized pledge has no normal cancellation or refund path, and an expired pending pledge also prevents ordinary node removal. A delayed, admissible acceptance certificate with an eligible timestamp can still resolve that state, and the README points to the Kernel node operations document before you commit a pledge.
Addresses are XIN plus two keys, and transactions are version 5
A Mixin address begins with XIN and contains public view and spend keys. Generating one and decoding one are both single commands.
./mixin createaddress./mixin decodeaddress --address XIN_ADDRESSThe private view key discovers received outputs, while spending also requires the private spend key, and the README insists both are kept secret and backed up. There is a second form, createaddress --public, which deterministically derives the view key from the public spend key. Kernel uses that form for public node signer and payee identities, and the README says to use it only when public observability is intentional. That is a privacy decision with a technical mechanism behind it, not a style choice.
On the transaction side, version 5 with deterministic binary encoding. An ordinary transfer consumes earlier UTXOs of one asset, creates one or more threshold-script outputs, and is signed over the unsigned payload hash. Output amounts must sum exactly to the input amounts, and the builder requires an explicit change output when one is needed. The workflow is documented as a single shell pipeline:
RAW=$(./mixin --node http://127.0.0.1:6860 buildrawtransaction \
--asset ASSET_ID \
--inputs SOURCE_TRANSACTION_HASH:0 \
--outputs XIN_RECIPIENT_ADDRESS:1.00000000 \
--view PRIVATE_VIEW_KEY \
--spend PRIVATE_SPEND_KEY)
./mixin decoderawtransaction --raw "$RAW"
./mixin --node http://127.0.0.1:6860 sendrawtransaction --raw "$RAW"The README is blunt about the risk in that example: command-line arguments may be visible to other local users through process inspection or shell history, so production wallets should protect private keys and use the transaction packages directly or an appropriately isolated signing process. That is the difference between a demo command and a wallet.
A GPL-3.0 licence, a forked storage engine, and a gap between releases and commits
The licence is GPL-3.0, with a LICENSE file at the repository root. For an organisation that wants to run this as a service or to link pieces of it into a product, that is the term to read first, and this description is not a legal opinion.
The dependency list deserves attention for a different reason. go.mod replaces github.com/dgraph-io/badger/v4 with github.com/MixinNetwork/badger/v4 v4.9.6-F1. The storage engine the kernel depends on is not the upstream project but a fork maintained under the Mixin organisation, and the replace directive points at it. The module also pulls in quic-go, urfave/cli/v2, pelletier/go-toml, shopspring/decimal, zeebo/blake3 and ristretto, and the repository vendors its dependencies in a vendor/ directory, so the tree you clone builds without fetching modules at build time.
On releases, the picture is unusual. The recent releases are v0.16.10, v0.16.9 and v0.16.8, all published in October 2023 within about two weeks of each other. The last push to the repository, however, was on 2026-09-28. So the commit line has moved on substantially since the last tagged release. If you want a named version, the newest tag is from 2023; if you want current code, you are taking the branch, and the two are not the same thing.
The repository layout supports the reading that this is a project documented for readers. There are MAO.md, STORAGE.md, INSCRIPTION.md and CHANGELOG.md at the root, a doc/ directory with the technical paper and the operations documents, and separate kernel/, p2p/, rpc/, storage/, crypto/ and config/ packages in the source tree.
Editorial conclusion
Mixin Kernel fits an engineer who wants to read a working ledger implementation end to end, run a seven-node network on one machine, and understand snapshot certification and UTXO finalization without a production chain, and it does not fit an application that needs custodial deposits or external-chain withdrawals handled for it, since those depend on separate custody services. Verify first that you build with make rather than plain go build, that you set node.signer-key and p2p.relayer deliberately in config.toml, and that the 13,439 XIN pledge and its seven-day acceptance window fit your plan before you submit one.
Frequently asked questions
What is Mixin Kernel?
It is the reference implementation of the Mixin network, a distributed ledger for digital assets combining a UTXO state model, parallel per-node chains, a cross-referenced DAG and collective signatures for Byzantine-fault-tolerant consensus.
How do I build the mixin binary?
Install the Go version declared in go.mod, which is go 1.27.1, and run make from a clean checkout. The Makefile stamps the Git commit into config/reader.go before compiling and restores it afterwards, and a binary built with plain go build refuses to start while its version still contains BUILD_VERSION.
How do I run a local Mixin test network?
Run ./mixin setuptestnet, which generates configuration for a seven-node test network under /tmp/mixin-6861 to /tmp/mixin-6867 and prints the genesis document, network identifier and test custodian credentials. Start each node with ./mixin kernel --dir pointing at its own directory; the nodes use P2P UDP ports 5851 to 5857 and RPC TCP ports 6861 to 6867.
What does joining the Mixin consensus set require?
A 13,439 XIN pledge and the automated acceptance sequence, with acceptance having to satisfy the seven-day pledge-to-accept timestamp limit. A finalized pledge has no normal cancellation or refund path, and an expired pending pledge also prevents ordinary node removal.
How does Mixin confirm that a transaction is final?
A successful sendrawtransaction response alone does not establish finalization. gettransaction includes a snapshot field when the queried node records the transaction as finalized, and RPC results reflect the selected node's view.
Who handles deposits and external-chain withdrawals in Mixin?
Not the kernel. Asset deposits require custodian authorization, and checking external reserves and executing external-chain withdrawals depend on separate custody services.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mixinnetwork-mixin)Was this useful?