diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 1d37f64..c701428 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -2,6 +2,8 @@ package blockchain import ( "encoding/json" + "log" + "strings" "github.com/stinkymonkeyph/gopher-blocks/constants" ) @@ -33,3 +35,45 @@ func (bc *Blockchain) AddTransactionToTransactionPool(txn *Transaction) { txn.Status = constants.STATUS_PENDING bc.TransactionPool = append(bc.TransactionPool, txn) } + +func (bc *Blockchain) AddBlock(b *Block) { + m := map[string]bool{} + for _, txn := range b.Transactions { + m[txn.TransactioHash] = true + } + + for idx, txn := range bc.TransactionPool { + _, ok := m[txn.TransactioHash] + + if ok { + bc.TransactionPool = append(bc.TransactionPool[:idx], bc.TransactionPool[idx+1:]...) + } + } + + bc.Blocks = append(bc.Blocks, b) +} + +func (bc *Blockchain) ProofOfWorkMining(minerAddress string) { + nonce := 0 + for { + prevHash := bc.Blocks[len(bc.Blocks)-1].Hash() + guessBlock := NewBlock(prevHash, nonce) + + for _, txn := range bc.TransactionPool { + tx := NewTransaction(txn.From, txn.To, txn.Value, txn.Data) + guessBlock.AddTransactionToTheBlock(tx) + } + + zeroes := strings.Repeat("0", constants.MINING_DIFFICULTY) + guessHash := guessBlock.Hash() + + if zeroes == guessHash[2:2+constants.MINING_DIFFICULTY] { + rewardTxn := NewTransaction(constants.BLOCKCHAIN_REWARD_ADDRESS, minerAddress, constants.MINING_REWARD, []byte{}) + guessBlock.Transactions = append(guessBlock.Transactions, rewardTxn) + bc.AddBlock(guessBlock) + log.Printf(bc.ToJSON(), "\n\n") + nonce = 0 + continue + } + } +} diff --git a/blockchain/transaction.go b/blockchain/transaction.go index b633443..44dd7fd 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -1,16 +1,21 @@ package blockchain import ( + "crypto/sha256" + "encoding/hex" "encoding/json" "math" + + "github.com/stinkymonkeyph/gopher-blocks/constants" ) type Transaction struct { - From string `json:"from"` - To string `json:"to"` - Value uint64 `json:"value"` - Data []byte `json:"data"` - Status string `json:"status"` + From string `json:"from"` + To string `json:"to"` + Value uint64 `json:"value"` + Data []byte `json:"data"` + Status string `json:"status"` + TransactioHash string `json:"transaction_hash"` } func NewTransaction(from string, to string, value uint64, data []byte) *Transaction { @@ -19,7 +24,7 @@ func NewTransaction(from string, to string, value uint64, data []byte) *Transact t.To = to t.Value = value t.Data = data - + t.TransactioHash = "" return t } @@ -46,3 +51,17 @@ func (t *Transaction) VerifyTransaction() bool { return true } + +func (t *Transaction) Hash() string { + ts, err := json.Marshal(t) + + if err != nil { + panic("Something went wrong while serializing transaction object") + } + + sum := sha256.Sum256(ts) + hex := hex.EncodeToString(sum[:32]) + hex = constants.HEX_PREFIX + hex + + return hex +} diff --git a/constants/constants.go b/constants/constants.go index c0f6236..622f052 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -1,9 +1,14 @@ package constants const ( - BLOCKCHAIN_NAME = "GopherBlocks" - HEX_PREFIX = "0x" - STATUS_SUCCESS = "success" - STATUS_FAILED = "failed" - STATUS_PENDING = "pending" + BLOCKCHAIN_NAME = "GopherBlocks" + HEX_PREFIX = "0x" + STATUS_SUCCESS = "success" + STATUS_FAILED = "failed" + STATUS_PENDING = "pending" + MINING_DIFFICULTY = 4 + MINING_REWARD = 1200 * DECIMAL + CURRENCY_NAME = "gopher" + DECIMAL = 100 + BLOCKCHAIN_REWARD_ADDRESS = "Gopher_Reward_Pool" ) diff --git a/main.go b/main.go index bca4a7b..2b5d51a 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,8 @@ package main import ( "log" + "sync" + "time" "github.com/stinkymonkeyph/gopher-blocks/blockchain" "github.com/stinkymonkeyph/gopher-blocks/constants" @@ -12,7 +14,17 @@ func init() { } func main() { + + var wg sync.WaitGroup + block := blockchain.NewBlock("0x0", 0) + transaction1 := blockchain.NewTransaction("0x1", "0x2", 12, []byte{}) bc := blockchain.NewBlockchain(block) log.Print(bc.ToJSON()) + + wg.Add(1) + go bc.ProofOfWorkMining("alice") + time.Sleep(2000) + bc.AddTransactionToTransactionPool(transaction1) + wg.Wait() }