Blocks and Transactions

Understanding how blocks contain transactions and how transactions are structured.

Intermediate⏱️ 35 min📚 Prerequisites: 1

Blocks and Transactions

Transactions are the fundamental unit of data in a blockchain. Blocks are containers that hold multiple transactions.

Transaction Structure

A transaction typically contains:

  • Sender: Who is sending
  • Receiver: Who is receiving
  • Amount: How much is being transferred
  • Signature: Cryptographic proof of authorization
  • Timestamp: When the transaction occurred

Block Structure

A block contains:

  • Header: Metadata (index, timestamp, previous hash, merkle root)
  • Transactions: List of transactions
  • Hash: Cryptographic hash of the block

Transaction Example

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
    signature: String,
    timestamp: u64,
}

Block with Transactions

RUST
struct Block {
    index: u64,
    timestamp: u64,
    transactions: Vec<Transaction>,
    previous_hash: String,
    hash: String,
}

Transaction Validation

Before adding a transaction to a block, we must validate:

  1. Signature is valid: The sender authorized this transaction
  2. Sufficient balance: Sender has enough funds
  3. No double spending: Transaction hasn't been used before
  4. Format is correct: All fields are properly formatted

Code Examples

Transaction Structure

Creating and using transactions

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
    signature: String,
    timestamp: u64,
}
impl Transaction {
    fn new(from: String, to: String, amount: u64) -> Self {
        Transaction {
            from,
            to,
            amount,
            signature: String::from("pending"),
            timestamp: 1234567890,
        }
    }
    fn display(&self) {
        println!("{} -> {}: {} coins", self.from, self.to, self.amount);
    }
}
fn main() {
    let tx = Transaction::new(
        String::from("Alice"),
        String::from("Bob"),
        100,
    );
    tx.display();
}

Explanation:

Transactions represent value transfers. The signature field will be populated when the transaction is signed with the sender's private key.

Block with Transactions

Creating blocks that contain transactions

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
}
struct Block {
    index: u64,
    transactions: Vec<Transaction>,
    previous_hash: String,
    hash: String,
}
impl Block {
    fn new(index: u64, transactions: Vec<Transaction>, previous_hash: String) -> Self {
        Block {
            index,
            transactions,
            previous_hash,
            hash: String::from("calculated_hash"),
        }
    }
    fn transaction_count(&self) -> usize {
        self.transactions.len()
    }
}
fn main() {
    let transactions = vec![
        Transaction {
            from: String::from("Alice"),
            to: String::from("Bob"),
            amount: 50,
        },
        Transaction {
            from: String::from("Bob"),
            to: String::from("Charlie"),
            amount: 25,
        },
    ];
    let block = Block::new(1, transactions, String::from("prev_hash"));
    println!("Block contains {} transactions", block.transaction_count());
}

Explanation:

Blocks can contain multiple transactions. This allows batching multiple operations together, improving efficiency.

Exercises

Create Transactions

Create a block with multiple transactions!

Medium

Starter Code:

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
}
struct Block {
    index: u64,
    transactions: Vec<Transaction>,
    previous_hash: String,
}
fn main() {
}