From 3cb93b52785e54df7f09bad8bc8ec32c91fd5045 Mon Sep 17 00:00:00 2001 From: Ivan Kuznetsov Date: Tue, 3 Oct 2017 15:47:27 +0700 Subject: [PATCH] Implement 'tx' command (WIP) --- cli_send.go | 13 +++++++--- server.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ transaction.go | 13 ++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/cli_send.go b/cli_send.go index 4e5a59a..84b500a 100644 --- a/cli_send.go +++ b/cli_send.go @@ -25,9 +25,16 @@ func (cli *CLI) send(from, to string, amount int, nodeID string) { tx := NewUTXOTransaction(&wallet, to, amount, &UTXOSet) cbTx := NewCoinbaseTX(from, "") - txs := []*Transaction{cbTx, tx} + // txs := []*Transaction{cbTx, tx} - newBlock := bc.MineBlock(txs) - UTXOSet.Update(newBlock) + // var txHashes [][]byte + // txHashes = append(txHashes, tx.Hash()) + // txHashes = append(txHashes, cbTx.Hash()) + + sendTx(knownNodes[0], tx) + sendTx(knownNodes[0], cbTx) + + // newBlock := bc.MineBlock(txs) + // UTXOSet.Update(newBlock) fmt.Println("Success!") } diff --git a/server.go b/server.go index 22fb2dd..2d6577e 100644 --- a/server.go +++ b/server.go @@ -3,6 +3,7 @@ package main import ( "bytes" "encoding/gob" + "encoding/hex" "fmt" "io" "io/ioutil" @@ -17,6 +18,7 @@ const commandLength = 12 var nodeAddress string var knownNodes = []string{"localhost:3000"} var blocksInTransit = [][]byte{} +var mempool = make(map[string]Transaction) type addr struct { AddrList []string @@ -43,6 +45,11 @@ type inv struct { Items [][]byte } +type tx struct { + AddFrom string + Transaction []byte +} + type verzion struct { Version int BestHeight int @@ -133,6 +140,14 @@ func sendGetData(address, kind string, id []byte) { sendData(address, request) } +func sendTx(addr string, tnx *Transaction) { + data := tx{nodeAddress, tnx.Serialize()} + payload := gobEncode(data) + request := append(commandToBytes("tx"), payload...) + + sendData(addr, request) +} + func sendVersion(addr string, bc *Blockchain) { bestHeight := bc.GetBestHeight() payload := gobEncode(verzion{nodeVersion, bestHeight, nodeAddress}) @@ -213,6 +228,14 @@ func handleInv(request []byte, bc *Blockchain) { } blocksInTransit = newInTransit } + + if payload.Type == "tx" { + txID := payload.Items[0] + + if mempool[hex.EncodeToString(txID)].ID == nil { + sendGetData(payload.AddrFrom, "tx", txID) + } + } } func handleGetBlocks(request []byte, bc *Blockchain) { @@ -249,6 +272,51 @@ func handleGetData(request []byte, bc *Blockchain) { sendBlock(payload.AddrFrom, &block) } + + if payload.Type == "tx" { + txID := hex.EncodeToString(payload.ID) + tx := mempool[txID] + + sendTx(payload.AddrFrom, &tx) + // delete(mempool, txID) + } +} + +func handleTx(request []byte, bc *Blockchain) { + var buff bytes.Buffer + var payload tx + + buff.Write(request[commandLength:]) + dec := gob.NewDecoder(&buff) + err := dec.Decode(&payload) + if err != nil { + log.Panic(err) + } + + txData := payload.Transaction + tx := DeserializeTransaction(txData) + mempool[hex.EncodeToString(tx.ID)] = tx + + if nodeAddress == knownNodes[0] { + for _, node := range knownNodes { + if node != nodeAddress { + sendInv(node, "tx", [][]byte{tx.ID}) + } + } + } else { + if len(mempool) >= 2 { + var txs []*Transaction + + for _, tx := range mempool { + txs = append(txs, &tx) + } + newBlock := bc.MineBlock(txs) + UTXOSet := UTXOSet{bc} + UTXOSet.Update(newBlock) + + mempool = make(map[string]Transaction) + } + } } func handleVersion(request []byte, bc *Blockchain) { @@ -296,6 +364,8 @@ func handleConnection(conn net.Conn, bc *Blockchain) { handleGetBlocks(request, bc) case "getdata": handleGetData(request, bc) + case "tx": + handleTx(request, bc) case "version": handleVersion(request, bc) default: diff --git a/transaction.go b/transaction.go index 0da2117..a982384 100644 --- a/transaction.go +++ b/transaction.go @@ -228,3 +228,16 @@ func NewUTXOTransaction(wallet *Wallet, to string, amount int, UTXOSet *UTXOSet) return &tx } + +// DeserializeTransaction deserializes a transaction +func DeserializeTransaction(data []byte) Transaction { + var transaction Transaction + + decoder := gob.NewDecoder(bytes.NewReader(data)) + err := decoder.Decode(&transaction) + if err != nil { + log.Panic(err) + } + + return transaction +}