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
RUSTstruct Transaction { from: String, to: String, amount: u64, signature: String, timestamp: u64, }
Block with Transactions
RUSTstruct 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:
- Signature is valid: The sender authorized this transaction
- Sufficient balance: Sender has enough funds
- No double spending: Transaction hasn't been used before
- 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!
Starter Code:
RUST
struct Transaction {
from: String,
to: String,
amount: u64,
}
struct Block {
index: u64,
transactions: Vec<Transaction>,
previous_hash: String,
}
fn main() {
}