block

package
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 28, 2020 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Base58Decode

func Base58Decode(input []byte) []byte

Base58Decode decodes Base58-encoded data

func Base58Encode

func Base58Encode(input []byte) []byte

Base58Encode encodes a byte array to Base58

func DBExists

func DBExists() bool

DBExists checks whether bolt has a db created. If yes that means there is a blockchain already created

func HashPubKey

func HashPubKey(pubKey []byte) []byte

HashPubKey takes in a public key slice. It first hashes with SHA256, and then hashes it again with RIPEMD160

func IntToHex

func IntToHex(n int64) []byte

IntToHex takes in an int64 and returns a byte slice of that int64 formatted to base16

func ReverseBytes

func ReverseBytes(data []byte)

ReverseBytes reverses a byte array

func ValidateAddress

func ValidateAddress(address string) bool

Types

type Block

type Block struct {
	Timestamp     int64
	Transactions  []*Transaction
	PrevBlockHash []byte
	Hash          []byte
	Nonce         int
}

Block represents a single block withing a blockchain. A block contains headers, and the body (transactions). A block always references the previous block in a chain.

func DeserializeBlock

func DeserializeBlock(d []byte) *Block

Deserialize decodes a serialized block

func NewBlock

func NewBlock(transactions []*Transaction, prevBlockHash []byte) *Block

NewBlock takes in a list of transactions, and the previous blocks hash, and creates a new block.

func NewGenesisBlock

func NewGenesisBlock(coinbase *Transaction) *Block

NewGenesisBlock creates a new genesis block. The genesis block is the initial block created when a blockchain is created.

func (*Block) HashTransactions

func (b *Block) HashTransactions() []byte

HashTransactions joins together a slice of transaction ID's, and hashes them together. Used when preparing a blocks data. Notice the merkle tree. Instead of saving all transactions and hashing them together, we use a merkle tree instead.

func (*Block) Serialize

func (b *Block) Serialize() []byte

Serialize serializes/encodes a block

type Blockchain

type Blockchain struct {
	Tip []byte   // Tip is the hash of the latest block added to the blockchain
	DB  *bolt.DB // DB is a reference to a boltDB connection
}

Blockchain represents an entire blockchain. It stores the tip/tail/(hash of the last block) in a blockchain.

func CreateBlockchain

func CreateBlockchain(address string) *Blockchain

CreateBlockchain creates a blockchain. It first creates a genesis block, and signs the output with the address of the creator.

func NewBlockChain

func NewBlockChain(address string) *Blockchain

NewBlockChain doesn't create a blockchain, instead it identifies the tail of a previous blockchain, and that becomes the starting point of the new blockchain.

func (*Blockchain) FindTransaction

func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error)

FindTransaction finds a specific transaction across the entire blockchain by its ID.

func (*Blockchain) FindUTXO

func (bc *Blockchain) FindUTXO() map[string]TXOutputs

FindUnspentTransactions loops over every block in a blockchain. For every transaction, it checks for unspent transactions. For every Output in a transaction, check if that output was already "spent"/referenced by an input. The first/tail block will always be nil since no outputs have been referenced. Then add the transaction to the UTXOs map if unreferenced. The next time the loops runs, when it looks for free outputs, if they are on that map they are definitely not free.

func (*Blockchain) Iterator

func (bc *Blockchain) Iterator() *BlockchainIterator

Iterator returns an iterator for a Blockchain

func (*Blockchain) MineBlock

func (bc *Blockchain) MineBlock(transactions []*Transaction) *Block

MineBlock takes in a list of transactions, finds the last hash of a blockchain, and creates a new block with the transactions and last hash. Then it updates the db and inserts the block, and updates the tail to be the hash of this new block.

func (*Blockchain) SignTransaction

func (bc *Blockchain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey)

SignTransaction signs a transaction using the Sign method. It takes in the transaction to be signed and the private key to sign with.

func (*Blockchain) VerifyTransaction

func (bc *Blockchain) VerifyTransaction(tx *Transaction) bool

Verify transaction verifies a transaction by using the Verify method. It uses the signature and public key stored in the input to verify the entire transaction.

type BlockchainIterator

type BlockchainIterator struct {
	DB *bolt.DB // DB is a reference to a boltDB connection
	// contains filtered or unexported fields
}

BlockchainIterator stores the current hash of the block you are about to iterate over

func (*BlockchainIterator) Next

func (i *BlockchainIterator) Next() *Block

Next is a method of BlockchainIterator that grabs the next block based on a hash. I.e, block A has a hash "abcd" and a lastHash of "wxyz". Iterator has currentHash as "abcd", it first finds the block with hash "abcd", which is block A, and then sets currentHash to the lastHash of block A, which is "wxyz". The next time iterator is callled, it searches for "wxyz", and stores that blocks lastHash in currentHash.

type MerkleNode

type MerkleNode struct {
	Left  *MerkleNode
	Right *MerkleNode
	Data  []byte
}

MerkleNode is an instance of a MerkleNode. It can contain two other MerkleNode(s), each one corresponding to the left and right of this MerkleNode. It also contains some data, which is a sha256 hash.

func NewMerkleNode

func NewMerkleNode(left, right *MerkleNode, data []byte) *MerkleNode

NewMerkleNode takes in a left and right node, and some data. The data is used when creating the initial leaf nodes, and it's a serialized transaction. If it's a lead node, i.e: left and right are nil, then hash the data and store is as nMode.Data. If it's not a leaf node, concatenate the left and right, which are just the two nodes below this new node that actually form this node, and then hash them and then that's your new node's data.

type MerkleTree

type MerkleTree struct {
	RootNode *MerkleNode // RootNode is the top most node of a MerkleTree.
}

MerkleTree is an instance of a MerkleTree.

func NewMerkleTree

func NewMerkleTree(data [][]byte) *MerkleTree

NewMerkleTree creates a new merkle tree. The data passed is a slice of serialized transactions. Before anything, if the amount of tx is odd, duplicate the last one. The merkle tree afterwards creates a leaf node for every transaction, and those leaf nodes contain a hash of the transaction as their data. Next, we run a loop for half the amount of transactions.

type ProofOfWork

type ProofOfWork struct {
	// contains filtered or unexported fields
}

ProofOfWork represent a single ProofOfWork instance.

func NewProofOfWork

func NewProofOfWork(b *Block) *ProofOfWork

NewProofOfWork takes in a block and returns a ProofOfWork. the PoW target is set to the largest number allowed. For example, if we only want to allow hashes smaller than 1000, only if the hash is 999 or less will it pass. The target is 256 - targetBits. 256 since the hashing algorithm returns maximum 256 bits. Which is 32 bytes. If targetBits is 24, then the maximum number of bits is 232 which is 29 bytes. Any hash smaller than 29 bytes will be accepted. The smaller targetBits is, the easier it is to mine a new block.

func (*ProofOfWork) PrepareData

func (pow *ProofOfWork) PrepareData(nonce int) []byte

PrepareData takes in nonce, and returns a byte slice. The nonce is an int, that when added to the blocks hash, returns a hash that meets the requirement of the target. The byte slice returned is a slice of a blocks previous hash, transactions, timestamp, targetBits, and nonce.

func (*ProofOfWork) Run

func (pow *ProofOfWork) Run() (int, []byte)

Run is a method of ProofOfWork. Run is the method that actually does what we call "mine". It's an incredibly memory intensive task, since it runs, checks if true, and if not, keeps running until true. The maximum value it can run until, is until the largest number an int64 can be. Every time the hash is greater than the target, the for loop increases nonce by 1. Each time it runs it first gets a byte slice of all the data, by calling PrepareData, then it hashes it using sha256, then checks to see if it satisfies the target.

func (*ProofOfWork) Validate

func (pow *ProofOfWork) Validate() bool

Validate is a method that verifies that the hash of a block is actual less than its target.

type TXInput

type TXInput struct {
	Txid      []byte // the id of the transaction that contains the output this input is referencing
	Vout      int    // index of the output it is referencing
	Signature []byte // signature is propagated when the transaction is signed, and it's a concatenated key pair generated using a private key and a trimmed transaction hash
	PubKey    []byte // the public key of the sender. i.e: the one who owns the output
}

TXInput represents a single input. An input must always reference an output. The input contains an id of which transaction it references, and the index of which output within that referenced transaction. It also contains the address/signature of who spent the coins. An input means that coins were spent/send/transferred.

func (*TXInput) UsesKey

func (in *TXInput) UsesKey(pubKeyHash []byte) bool

UsesKey checks if the inputs lock hash matches the hash of the public key. If yes then it belongs to that address. pubKeyHash is just the public key hashed, without any added version or checksum

type TXOutput

type TXOutput struct {
	Value      int    // amount of "coins" on the outputs
	PubKeyHash []byte // this hash is the public key hash of the guy who owns the output
}

TXOutput represents a single transaction output. TXOutputs store "coins", and are locked by a public key. The key can only be unlocked by the coins owner. Outputs that are referenced are spent and can't be used. Unreferenced outputs are open to being sent/spent/transferred.

func NewTXOutput

func NewTXOutput(value int, address string) *TXOutput

NewTXOutput takes in a value and address, and creates a new TX output. It locks the transaction output to the address inputted.

func (*TXOutput) IsLockedWithKey

func (out *TXOutput) IsLockedWithKey(pubKey []byte) bool

IsLockedWithKey checks if the output was locked with the public key it's being tested against. pubKey is the hashed public key without version or checksum

func (*TXOutput) Lock

func (out *TXOutput) Lock(address []byte)

Lock takes in an address, decodes it, removes the version and checksum, and then assigns it to the outputs public key. Only this address can now unlock the output. address here is the base58 encoded version+hash+checksum, part of the functions logic is to decode, and remove the version and checksum

type TXOutputs

type TXOutputs struct {
	Outputs []TXOutput // slice of TX Outputs.
}

TXOutputs is an instance of a slice of transaction outputs.

func DeserializeOutputs

func DeserializeOutputs(data []byte) TXOutputs

DeserializeOutputs takes in a byte slice of serialized outputs, and returns the decoded outputs as TXOutputs.

func (TXOutputs) Serialize

func (outs TXOutputs) Serialize() []byte

Serialize takes in a slice of TXOutputs and serializes them.

type Transaction

type Transaction struct {
	ID   []byte     // ID of the transaction. It's how its identified.
	Vin  []TXInput  // list of inputs // inputs always reference an output
	Vout []TXOutput // list of outputs // outputs that are referenced are "taken", unreferenced outputs have a value that can be spent
}

Transaction represents a single transaction

func NewCoinbaseTX

func NewCoinbaseTX(to, data string) *Transaction

NewCoinbaseTX creates a new transaction for the initial genesis block

func NewUTXOTransaction

func NewUTXOTransaction(from, to string, amount int, UTXOSet *UTXOSet) *Transaction

New UTXOTransaction makes a transaction from address a to address b. It first gets a list of which outputs have address a's coins. If there aren't enough coins to satisfy the amount that address a would like to send, return an error that address a needs more coins. Otherwise, create an input that references the output that has address a's coins. Then create an output that has the amount being transferred, and lock it to address b. If there are too many coins on the output, i.e address a wants to send 5 and the output has 10, create another output locked to address a, and store the remainder of the coins on that new output. Finally, using the newly created input and output(s), return a transaction that can then be stored in a block.

func (*Transaction) Hash

func (tx *Transaction) Hash() []byte

Hash hashes a transaction, to be used for setting a transaction's ID.

func (Transaction) IsCoinbase

func (tx Transaction) IsCoinbase() bool

IsCoinbase checks if it's the outputs from the genesis block

func (Transaction) Serialize

func (tx Transaction) Serialize() []byte

Serialize serializes an entire transaction. Used when inserting a transaction into a boltDB bucket, or when hashing.

func (*Transaction) Sign

func (tx *Transaction) Sign(privateKey ecdsa.PrivateKey, prevTXs map[string]Transaction)

Sign takes in a private key and a list of previous transactions, and signs the transaction it was called with. The private key is used to do the signing, while the prevTXs is map holding transactions that contain outputs. Those outputs are the outputs that the transaction you are calling this method from has referenced.

func (*Transaction) TrimmedCopy

func (tx *Transaction) TrimmedCopy() Transaction

TrimmedCopy removes the Signature and PubKey from a transaction and sets them to nil. We don't need to sign the input keys, only the output keys

func (*Transaction) Verify

func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool

Verify is used to verify a transactions signature is valid. Like Sign, prevTXs is a map of transactions that contain the outputs that THE transaction's inputs referenced.

type UTXOSet

type UTXOSet struct {
	Blockchain *Blockchain
}

UTXOSet is a struct that contains only a reference to a blockchain instance.

func (UTXOSet) FindSpendableOutputs

func (u UTXOSet) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int)

FindSpendableOutputs runs through the utxo bucket, and checks if there are any UTXO's that are owned by the address requesting them.

func (UTXOSet) FindUTXO

func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput

FindUTXO is a method of UTXOSet, not to be confused with the Blockchain method of the same name. This FindUTXO is used to get the balance of an address. FindSpendableOutputs finds the first x amount of outputs that contain enough coins to satisfy the transfer. This function checks through every output.

func (UTXOSet) Reindex

func (u UTXOSet) Reindex()

Reindex is used to reindex the chainstate. This is a pretty intensive task, so use wisely.

func (UTXOSet) Update

func (u UTXOSet) Update(block *Block)

Update is used to update the utxoBucket when there are newly referenced or created outputs. Pretty much every time a transaction is made, and also when a new block is added to the chain. Find the outputs on a TX that an input references, and then if they don't match the index in the input, that output is free.

type Wallet

type Wallet struct {
	PrivateKey ecdsa.PrivateKey // this private key is a struct containing both a private and public key. A private key is never stored in a database, it should remain... private.
	PublicKey  []byte           // this public key is not hashed. It's generated when you create a private key, and really consists of two parts that are concatenated
}

Wallet represents a single wallet instance. A wallet contains a private key and a public key

func NewWallet

func NewWallet() *Wallet

NewWallet returns a wallet struct, with a private and public key

func (Wallet) GetAddress

func (w Wallet) GetAddress() []byte

GetAddress is responsible for getting an address for a wallet. It first runs the public key though a RIPEMD160 hash of a SHA256 hash of the public key. Then it appends the version to the head of the public key. Next, a checksum 4 bytes long is created, by double hashing the version+publicKey. The full payload is then created by appending the checksum to the end of the version+publicKey. Finally that value is base58 encoded and returned as the address.

type Wallets

type Wallets struct {
	Wallets map[string]*Wallet
}

Wallets is an instance of multiple Wallet('s). More specifically it is a map of a wallets address to a Wallet struct. i.e : [197QdQzchU4aMF3pTryySADwCsSC6cpj4A:*Wallet]

func NewWallets

func NewWallets() (*Wallets, error)

NewWallets loads in all the wallets stored in the wallet.dat file

func (*Wallets) CreateWallet

func (ws *Wallets) CreateWallet() string

CreateWallet creates a new wallet, gets its address using GetAddress, and then sets the wallet to be included in the the Wallets struct, and finally returns the address

func (Wallets) GetWallet

func (ws Wallets) GetWallet(address string) Wallet

GetWallet gets a specific wallet within a map of wallets. It takes in the wallet address, and returns the wallet

func (*Wallets) LoadFromFile

func (ws *Wallets) LoadFromFile() error

LoadFromFile checks if wallet.dat exists, and reads in the contents. The wallets are gob encoded, so it first decodes them.

func (Wallets) SaveToFile

func (ws Wallets) SaveToFile()

SaveToFile saves a map of wallets to wallet.dat file. It firsts encodes them and then saves them to file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL