From 3d5c33ee1485be6d5554c4f31c63f78453e26b4d Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Mon, 11 Jun 2018 00:07:32 -0700 Subject: [PATCH] add CreateBlockchain --- block.go | 44 +++++++++++++++++----------------- blockchain.go | 14 +++++++++++ transaction.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 26 deletions(-) diff --git a/block.go b/block.go index c330db6ad..bf99487b1 100644 --- a/block.go +++ b/block.go @@ -16,6 +16,28 @@ type Block struct { Hash []byte } +// Serialize serializes the block +func (b *Block) Serialize() []byte { + var result bytes.Buffer + encoder := gob.NewEncoder(&result) + err := encoder.Encode(b) + if err != nil { + log.Panic(err) + } + return result.Bytes() +} + +// DeserializeBlock deserializes a block +func DeserializeBlock(d []byte) *Block { + var block Block + decoder := gob.NewDecoder(bytes.NewReader(d)) + err := decoder.Decode(&block) + if err != nil { + log.Panic(err) + } + return &block +} + // HashTransactions returns a hash of the transactions in the block func (b *Block) HashTransactions() []byte { var txHashes [][]byte @@ -28,17 +50,6 @@ func (b *Block) HashTransactions() []byte { return txHash[:] } -// Serialize serializes the block -func (b *Block) Serialize() []byte { - var result bytes.Buffer - encoder := gob.NewEncoder(&result) - err := encoder.Encode(b) - if err != nil { - log.Panic(err) - } - return result.Bytes() -} - // NewBlock creates and returns Block. func NewBlock(transactions []*Transaction, prevBlockHash []byte) *Block { block := &Block{time.Now().Unix(), transactions, prevBlockHash, []byte{}, 0} @@ -50,14 +61,3 @@ func NewBlock(transactions []*Transaction, prevBlockHash []byte) *Block { func NewGenesisBlock(coinbase *Transaction) *Block { return NewBlock([]*Transaction{coinbase}, []byte{}) } - -// DeserializeBlock deserializes a block -func DeserializeBlock(d []byte) *Block { - var block Block - decoder := gob.NewDecoder(bytes.NewReader(d)) - err := decoder.Decode(&block) - if err != nil { - log.Panic(err) - } - return &block -} diff --git a/blockchain.go b/blockchain.go index c3d5e128c..7365bc6d0 100644 --- a/blockchain.go +++ b/blockchain.go @@ -9,6 +9,8 @@ type Blockchain struct { blocks []*Block } +const genesisCoinbaseData = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks" + // NewBlockchain creates a new Blockchain with genesis Block func NewBlockchain(address string) *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}} @@ -87,3 +89,15 @@ Work: return accumulated, unspentOutputs } + +// CreateBlockchain creates a new blockchain DB +func CreateBlockchain(address string) *Blockchain { + // TODO: We assume we have not created any blockchain before. + // In current bitcoin, we can check if we created a blockchain before accessing local db. + cbtx := NewCoinbaseTX(address, genesisCoinbaseData) + genesis := NewGenesisBlock(cbtx) + + bc := Blockchain{[]*Block{genesis}} + + return &bc +} diff --git a/transaction.go b/transaction.go index f37fdc7f4..51480aad3 100644 --- a/transaction.go +++ b/transaction.go @@ -4,6 +4,8 @@ import ( "bytes" "crypto/sha256" "encoding/gob" + "encoding/hex" + "fmt" "log" ) @@ -14,19 +16,24 @@ type Transaction struct { txOutput []TXOutput } +// TXOutput is the struct of transaction output in a transaction. type TXOutput struct { - address string value int + address string } +// TXInput is the struct of transaction input in a transaction. type TXInput struct { - txId []byte + txID []byte txOutputIndex int address string } +// defaultCoinbaseValue is the default value of coinbase transaction. +const defaultCoinbaseValue = 10 + // SetID sets ID of a transaction -func (tx *Transaction) SetId() { +func (tx *Transaction) SetID() { var encoded bytes.Buffer var hash [32]byte @@ -36,5 +43,55 @@ func (tx *Transaction) SetId() { log.Panic(err) } hash = sha256.Sum256(encoded.Bytes()) - tx.ID = hash[:] + tx.id = hash[:] +} + +// NewCoinbaseTX creates a new coinbase transaction +func NewCoinbaseTX(to, data string) *Transaction { + if data == "" { + data = fmt.Sprintf("Reward to '%s'", to) + } + + txin := TXInput{[]byte{}, -1, data} + txout := TXOutput{defaultCoinbaseValue, to} + tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}} + tx.SetID() + + return &tx +} + +// NewUTXOTransaction creates a new transaction +func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { + var inputs []TXInput + var outputs []TXOutput + + acc, validOutputs := bc.FindSpendableOutputs(from, amount) + + if acc < amount { + log.Panic("ERROR: Not enough funds") + } + + // Build a list of inputs + for txid, outs := range validOutputs { + txID, err := hex.DecodeString(txid) + if err != nil { + log.Panic(err) + } + + for _, out := range outs { + input := TXInput{txID, out, from} + inputs = append(inputs, input) + } + } + + // Build a list of outputs + outputs = append(outputs, TXOutput{amount, to}) + if acc > amount { + outputs = append(outputs, TXOutput{acc - amount, from}) // a change + } + + tx := Transaction{nil, inputs, outputs} + tx.SetID() + + return &tx }