Convert Figma logo to code with AI

jamesob logotinychain

A pocket-sized implementation of Bitcoin

1,450
124
1,450
10

Top Related Projects

4,940

Zcash - Internet Money

78,874

Bitcoin Core integration/staging tree

Go implementation of the Ethereum protocol

4,497

Decentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C++

Reference implementation for the peer-to-peer agent that manages the Stellar network.

8,943

Monero: the secure, private, untraceable cryptocurrency

Quick Overview

tinychain is a minimalist blockchain implementation written in Python. It serves as an educational tool to help understand the core concepts of blockchain technology, such as blocks, transactions, and consensus.

Pros

  • Simplicity: The codebase is relatively small and easy to understand, making it a great learning resource for those new to blockchain.
  • Educational Value: The project provides a clear and concise explanation of blockchain fundamentals, making it a valuable tool for educational purposes.
  • Customizable: The modular design of the project allows users to easily extend or modify the functionality to suit their specific needs.
  • Cross-platform: The project is written in Python, which is a widely-used and cross-platform programming language.

Cons

  • Limited Functionality: As a minimalist implementation, tinychain lacks many of the advanced features found in production-ready blockchain platforms.
  • Performance Limitations: Due to its simplicity, the project may not be suitable for high-performance or large-scale blockchain applications.
  • Lack of Active Maintenance: The project appears to have limited active development, which could impact its long-term viability and support.
  • Python-specific: The project is written in Python, which may limit its appeal to developers who prefer other programming languages.

Code Examples

# Creating a new block
block = Block(
    index=0,
    timestamp=time.time(),
    transactions=[],
    previous_hash="0"
)

This code creates a new Block object with the specified parameters, including the index, timestamp, transactions, and the previous block's hash.

# Adding a transaction to the block
block.transactions.append(
    Transaction(
        sender="Alice",
        recipient="Bob",
        amount=10
    )
)

This code adds a new Transaction object to the block's list of transactions.

# Mining the block
block.mine(difficulty=2)

This code mines the block by finding a valid nonce that satisfies the specified difficulty level.

Getting Started

To get started with tinychain, follow these steps:

  1. Clone the repository:
git clone https://github.com/jamesob/tinychain.git
  1. Navigate to the project directory:
cd tinychain
  1. Install the required dependencies:
pip install -r requirements.txt
  1. Run the example script to see the blockchain in action:
python example.py

This will create a simple blockchain with a few blocks and transactions, and output the state of the blockchain to the console.

You can also explore the tinychain module and its various components, such as Block, Transaction, and Blockchain, to understand how the system works and experiment with your own modifications.

Competitor Comparisons

4,940

Zcash - Internet Money

Pros of Zcash

  • Zcash is a well-established and widely-adopted cryptocurrency, with a strong focus on privacy and security.
  • The project has a large and active community, with regular updates and improvements.
  • Zcash utilizes advanced cryptographic techniques, such as zk-SNARKs, to provide enhanced privacy features.

Cons of Zcash

  • Zcash is a more complex and resource-intensive project compared to Tinychain, which may make it less accessible for some users.
  • The privacy features of Zcash can also make it more challenging to audit and verify transactions.
  • Zcash has faced some regulatory challenges in certain jurisdictions due to its privacy-focused nature.

Code Comparison

Tinychain:

def create_block(self, transactions, prev_hash):
    block = {
        'index': len(self.chain) + 1,
        'timestamp': time.time(),
        'transactions': transactions,
        'prev_hash': prev_hash,
        'nonce': 0
    }
    self.chain.append(block)
    return block

Zcash:

fn create_block(
    &mut self,
    transactions: Vec<Transaction>,
    prev_hash: &Hash,
) -> Result<Block, Error> {
    let block = Block::new(
        self.chain.len() + 1,
        self.chain.last().map(|b| b.hash()),
        transactions,
        self.consensus.block_subsidy(self.chain.len() + 1),
    );
    self.chain.push(block.clone());
    Ok(block)
}
78,874

Bitcoin Core integration/staging tree

Pros of bitcoin/bitcoin

  • Extensive documentation and community support
  • Robust and well-tested codebase
  • Comprehensive set of features and functionalities

Cons of bitcoin/bitcoin

  • Complexity of the codebase, which can make it challenging for new contributors to get involved
  • Slower development pace compared to smaller, more agile projects
  • Potential for bureaucratic decision-making processes

Code Comparison

bitcoin/bitcoin:

bool CTransaction::CheckRegularTransaction(const CCoinsViewCache &inputs, CValidationState &state, bool fCheckDuplicateInputs) const
{
    // Basic checks that don't depend on any context
    if (!IsCoinBase() && (vin.empty() || vout.empty()))
        return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");

    // Size limits
    if (::GetSerializeSize(*this, PROTOCOL_VERSION) > MAX_BLOCK_WEIGHT / 4)
        return state.DoS(100, false, REJECT_INVALID, "bad-txn-size");
}

jamesob/tinychain:

def validate_tx(self, tx):
    """
    Validate a transaction.

    Args:
        tx (Transaction): The transaction to validate.

    Returns:
        bool: True if the transaction is valid, False otherwise.
    """
    # Check that all inputs have a corresponding output in the UTXO set
    for input in tx.inputs:
        if input.outpoint not in self.utxo:
            return False

    # Check that the sum of the input values is greater than or equal to the sum of the output values
    input_value = sum(self.utxo[input.outpoint].value for input in tx.inputs)
    output_value = sum(output.value for output in tx.outputs)
    if input_value < output_value:
        return False

    return True

The key differences between the two codebases are:

  • bitcoin/bitcoin is written in C++, while jamesob/tinychain is written in Python.
  • bitcoin/bitcoin has a more comprehensive and complex codebase, reflecting the maturity and feature-richness of the Bitcoin protocol.
  • jamesob/tinychain is a more lightweight and focused implementation, aimed at providing a basic understanding of blockchain concepts.

Go implementation of the Ethereum protocol

Pros of ethereum/go-ethereum

  • Comprehensive implementation of the Ethereum protocol, supporting a wide range of features and functionality.
  • Actively maintained and developed by a large community, ensuring ongoing improvements and bug fixes.
  • Extensive documentation and resources available for developers and users.

Cons of ethereum/go-ethereum

  • Larger codebase and complexity, which may make it more challenging for newcomers to understand and contribute to.
  • Potential performance issues or scalability limitations compared to smaller, more specialized blockchain projects.

Code Comparison

ethereum/go-ethereum:

func (s *Syncer) syncLoop() {
    defer s.wg.Done()

    for {
        select {
        case <-s.ctx.Done():
            return
        case <-s.syncTrigger:
            s.sync()
        }
    }
}

jamesob/tinychain:

def mine(self, block):
    """
    Attempts to mine the given block.

    Returns the mined block if successful, otherwise None.
    """
    while True:
        block.nonce += 1
        if self.valid_proof(block.transactions, block.prev_hash, block.nonce):
            block.hash = self.hash_block(block)
            return block
4,497

Decentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C++

Pros of rippled

  • Actively maintained and supported by the XRPL Foundation, a non-profit organization dedicated to the development and adoption of the XRP Ledger.
  • Extensive documentation and a large community of developers, making it easier to get started and find support.
  • Supports a wide range of features and functionality, including support for the XRP cryptocurrency and various decentralized applications.

Cons of rippled

  • Larger and more complex codebase compared to Tinychain, which may be a barrier for some developers.
  • Requires more resources (e.g., memory, storage) to run, which may be a limitation for some use cases.
  • Primarily focused on the XRP Ledger, which may not be suitable for developers interested in building on other blockchain platforms.

Code Comparison

Tinychain (jamesob/tinychain):

class Block:
    def __init__(self, index, timestamp, data, previous_hash):
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previous_hash = previous_hash
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        sha = hashlib.sha256()
        sha.update(str(self.index).encode('utf-8') +
                   str(self.timestamp).encode('utf-8') +
                   str(self.data).encode('utf-8') +
                   str(self.previous_hash).encode('utf-8'))
        return sha.hexdigest()

rippled (XRPLF/rippled):

void doValidation(
    std::shared_ptr<Ledger const> const& ledger,
    std::shared_ptr<STTx const> const& tx,
    std::shared_ptr<STObject> const& meta,
    Application& app)
{
    auto const result = app.getValidators().validate(
        *tx, *ledger, *meta, app.getHashRouter());

    if (result.first != Validity::Valid)
    {
        JLOG(app.journal("ValidatorManager").warn())
            << "Transaction " << tx->getTransactionID()
            << " is invalid: " << result.second;
    }
}

Reference implementation for the peer-to-peer agent that manages the Stellar network.

Pros of Stellar-core

  • Stellar-core is a production-ready, highly scalable, and secure blockchain platform, making it suitable for large-scale applications.
  • The project has a strong community and is actively maintained, with regular updates and bug fixes.
  • Stellar-core provides a comprehensive set of features, including support for multiple currencies, decentralized exchange, and smart contracts.

Cons of Stellar-core

  • Stellar-core has a steeper learning curve compared to Tinychain, which may be a barrier for some developers.
  • The codebase of Stellar-core is larger and more complex, which can make it more challenging to understand and contribute to.
  • Stellar-core may have a higher resource footprint compared to Tinychain, which could be a consideration for certain use cases.

Code Comparison

Tinychain (jamesob/tinychain):

class Block:
    def __init__(self, index, timestamp, data, previous_hash):
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previous_hash = previous_hash
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        sha = hashlib.sha256()
        sha.update(str(self.index).encode('utf-8') +
                   str(self.timestamp).encode('utf-8') +
                   str(self.data).encode('utf-8') +
                   str(self.previous_hash).encode('utf-8'))
        return sha.hexdigest()

Stellar-core (stellar/stellar-core):

void LedgerManager::startNewLedger()
{
    LedgerHeader lh;
    lh.ledgerVersion = CURRENT_LEDGER_VERSION;
    lh.previousLedgerHash = getLastClosedLedgerHeader().hash;
    lh.scpValue.closeTime = VirtualClock::to_time_t(mApp.getClock().now());
    lh.scpValue.txSetHash = SHA256::create()->finish();
    lh.scpValue.previousUpgradeTime = 0;
    lh.totalCoins = 0;
    lh.feePool = 0;
    lh.inflationSeq = 0;
    lh.idPool = 0;
    lh.baseFee = 0;
    lh.baseReserve = 0;
    lh.maxTxSetSize = 0;
    lh.skipList = {};
    storeLedgerHeader(lh);
}
8,943

Monero: the secure, private, untraceable cryptocurrency

Pros of Monero

  • Monero is a well-established and widely-used privacy-focused cryptocurrency, with a large and active community.
  • Monero has a strong focus on privacy and anonymity, using advanced cryptographic techniques to obfuscate transaction details.
  • Monero has a robust and actively maintained codebase, with regular updates and improvements.

Cons of Monero

  • Monero's codebase is significantly larger and more complex than Tinychain, which may make it more challenging for new contributors to get involved.
  • Monero's focus on privacy and anonymity may be a concern for some users or regulators, depending on the use case.
  • Monero's mining algorithm is designed to be ASIC-resistant, which may make it less attractive for large-scale mining operations.

Code Comparison

Tinychain (jamesob/tinychain):

def mine(self, block):
    """
    Mines a block by repeatedly hashing the block header until a valid
    nonce is found.
    """
    block.nonce = 0
    while True:
        block_hash = block.hash()
        if block_hash.startswith('0' * self.difficulty):
            return block_hash
        block.nonce += 1

Monero (monero-project/monero):

bool miner::mine_block_in_thread(const block& b, uint64_t height, uint64_t threads, uint64_t& nonce, uint64_t& target, crypto::hash& result_hash, bool& cancel)
{
    crypto::cn_slow_hash_v2(b.block_header.data(), b.block_header.size(), result_hash.data());
    if (check_hash(result_hash, target))
    {
        nonce = b.block_header.nonce;
        return true;
    }

    for (uint64_t i = 0; i < threads && !cancel; ++i)
    {
        ++b.block_header.nonce;
        crypto::cn_slow_hash_v2(b.block_header.data(), b.block_header.size(), result_hash.data());
        if (check_hash(result_hash, target))
        {
            nonce = b.block_header.nonce;
            return true;
        }
    }

    return false;
}

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

⛼ tinychain

Putting the rough in "rough consensus"

Tinychain is a pocket-sized implementation of Bitcoin. Its goal is to be a compact, understandable, working incarnation of the Nakamoto consensus algorithm at the expense of advanced functionality, speed, and any real usefulness.

I wrote it primarily to understand Bitcoin better, but hopefully it can serve as a jumping-off point for programmers who are interested in (but don't have intimate familiarity with) Bitcoin or cryptocurrency. At the very least, it can be a piñata for protocol developers who actually know what they're doing.

 $ cloc --quiet tinychain.py

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Python                           1            341            174            679
-------------------------------------------------------------------------------

Quick start

  • Install Docker & docker-compose
  • Clone this repo: git clone git@github.com:jamesob/tinychain.git
  • Make sure you're in a Python3.6 environment: virtualenv --python=python3.6 venv && . venv/bin/activate
  • Grab Python dependencies locally: pip install -r requirements.txt
  • Run docker-compose up. This will spawn two tinychain nodes.
  • In another window, run ./bin/sync_wallets. This brings the wallet data from the Docker containers onto your host.
    $ ./bin/sync_wallets
    
    Synced node1's wallet:
    [2017-08-05 12:59:34,423][tinychain:1075] INFO your address is 1898KEjkziq9uRCzaVUUoBwzhURt4nrbP8
     0.0 ⛼
    
    Synced node2's wallet:
    [2017-08-05 12:59:35,876][tinychain:1075] INFO your address is 15YxFVo4EuqvDJH8ey2bY352MVRVpH1yFD
    0.0 ⛼
    
  • Try running ./client.py balance -w wallet1.dat; try it with the other wallet file.
    $ ./client.py balance -w wallet2.dat
    
    [2017-08-05 13:00:37,317][tinychain:1075] INFO your address is 15YxFVo4EuqvDJH8ey2bY352MVRVpH1yFD
    0.0 ⛼
    
  • Once you see a few blocks go by, try sending some money between the wallets
    $ ./client.py send -w wallet2.dat 1898KEjkziq9uRCzaVUUoBwzhURt4nrbP8 1337
    
    [2017-08-05 13:08:08,251][tinychain:1077] INFO your address is 1Q2fBbg8XnnPiv1UHe44f2x9vf54YKXh7C
    [2017-08-05 13:08:08,361][client:105] INFO built txn Transaction(...)
    [2017-08-05 13:08:08,362][client:106] INFO broadcasting txn 2aa89204456207384851a4bbf8bde155eca7fcf30b833495d5b0541f84931919
    
  • Check on the status of the transaction
     $ ./client.py status e8f63eeeca32f9df28a3a62a366f63e8595cf70efb94710d43626ff4c0918a8a
    
     [2017-08-05 13:09:21,489][tinychain:1077] INFO your address is 1898KEjkziq9uRCzaVUUoBwzhURt4nrbP8
     Mined in 0000000726752f82af3d0f271fd61337035256051a9a1e5881e82d93d8e42d66 at height 5
    

What is Bitcoin?

In brief terms that map to this code...

Bitcoin is a way of generating pseudo-anonymous, decentralized trust at the cost of electricity. The most commonly known (but not sole) application of this is as a currency or store of value. If that sounds abstruse, general, and mindblowing, that's because it is.

In Bitcoin, value is recorded using a Transaction, which assigns some number of coins to an identity (via TxOuts) given some cryptographically unlocked TxIns. TxIns must always refer to previously created but unspent TxOuts.

A Transaction is written into history by being included in a Block. Each Block contains a data structure called a Merkle Tree which generates a fingerprint unique to the set of Transactions being included. The root of that Merkle tree is included in the block "header" and hashed (Block.id) to permanently seal the existence and inclusion of each Transaction in the block.

Blocks are linked together in a chain (active_chain) by referring to the previous Block header hash. In order to add a Block to the chain, the contents of its header must hash to a number under some difficulty target, which is set based upon how quickly recent blocks have been discovered (get_next_work_required()). This attempts to normalize the time between block discovery.

When a block is discovered, it creates a subsidy for the discoverer in the form of newly minted coins. The discoverer also collects fees from transactions included in the block, which are the value of inputs minus outputs. The block reward subsidy decreases logarithmically over time. Eventually the subsidy goes to zero and miners are incentivized to continue mining purely by a fee market.

Nodes in the network are in a never-ending competition to mine and propagate the next block, and in doing so facilitate the recording of transaction history. Transactions are submitted to nodes and broadcast across the network, stored temporarily in mempool where they are queued for block inclusion.

For more comprehensive descriptions of Bitcoin, see

Notable differences from Bitcoin

  • Byte-level representation and endianness are very important when serializing a data structure to be hashed in Bitcoin and are not reproduced faithfully here. In fact, serialization of any kind here is very dumbed down and based entirely on raw strings or JSON.

  • Transaction types are limited to pay-to-public-key-hash (P2PKH), which facilitate the bare minimum of "sending money." More exotic transaction types which allow m-of-n key signatures and Script-based unlocking are not implemented.

  • Initial Block Download is at best a simplified version of the old "blocks-first" scheme. It eschews getdata and instead returns block payloads directly in inv.

  • The longest, valid chain is determined simply by chain length (number of blocks) vs. chainwork.

  • Peer "discovery" is done through environment variable hardcoding. In bitcoin core, this is done with DNS seeds.

  • Replace by fee is absent.

  • Memory usage is egregious. Networking is a hack.

  • Satoshis are instead called Belushis because, well...

Q&A

How does RPC work?

We use JSON for over-the-wire serialization. It's slow and unrealistic but human-readable and easy. We deserialize right into the .*Msg classes, each of which dictates how a particular RPC message is handled via .handle().

Why doesn't the client track coins we've spent but haven't confirmed yet?

Yeah I know, the client sucks. I'll take a PR.

How can I add another RPC command to reveal more data from a node?

Just add a NamedTuple subclass with a handle() method defined; it registers automatically. Mimic any existing *Msg class.

Why aren't my changes changing anything?

Remember to rebuild the Docker container image when you make changes

docker-compose build && docker-compose up

How do I run automated tests?

pip install -r requirements.test.txt
py.test --cov test_tinychain.py

Is this yet another cryptocurrency created solely to Get Rich Quick™?

A resounding Yes! (if you're dealing in the very illiquid currency of education)

Otherwise nah. This thing has 0 real-world value.

What's with the logo?

It's a shitty unicode Merkle tree. Give a guy a break here, this is freeware!

Where can I get more of you ranting?

@jamesob