Richard Liu 7 years ago
commit 7159cd3445
  1. 4
      .travis.yml
  2. 2
      README.md
  3. 4
      blockchain/block_test.go
  4. 6
      blockchain/blockchain.go
  5. 13
      blockchain/blockchain_test.go
  6. 11
      blockchain/transaction.go
  7. 2
      blockchain/transaction_test.go
  8. 61
      blockchain/utxopool.go
  9. 2
      blockchain/utxopool_test.go
  10. 5
      consensus/consensus_leader.go

@ -1,5 +1,4 @@
language: go
go:
- master
install: |
@ -8,3 +7,6 @@ install: |
rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/harmony-benchmark/
export TRAVIS_BUILD_DIR=$HOME/gopath/src/harmony-benchmark
cd $HOME/gopath/src/harmony-benchmark
notifications:
slack:
secure: F6PRLJ7fIVpvZAEAIikE9u53CwklytznkNSJPuzB7cxLttAejls8ou3jsFFUkdTyyyy+QKFP9Bj+IFcAI9dq3CDYp7MnTQx/ajn8TC0xBwKW3gEKYoptIQJkXzvdwp9OanpU78QynRe1oRLefkN8qrL0zWLvoqcaHSYwjh1kzDCbO9G13aiI5CiFdW7jKwBKEPlleze4so0UdAaaGxyXUiSsmvHrOwF72ElnahKLy9DzmIgT8PdQkf1BmV3yaH3VQoU4fyu8t5P/jy8NYIXomcpo+pavgUBfXwd3mPf1KkAoB2RXdGCkORzHNZ6h+63ZVDzi1t8FWAbuNmvJ/Hq07IScGcsjZCEdy+79NSSBHThUejnHnqD4QdcXdhr30PoWBX85+phwPEVehAtddzgLyzivGByKHQMfWcetvPRww7Im+MpJW3OssgHlPxbRCE0uFtSDYgD9UoKevuZzFnME3U1rT9xqTweqOzxdsGRpvU/fLbh0PQCJnDQJjOB054l6ZTu9mtt+ogbYpOhB2PO6qLJZ64cn7M5/wLMiswRWooT9DeN+5a7n5MRo1i/TWFDFWBFYQVWTYdiTaU+oZdSZsu25TMboVraHPw3HE5tKIGgqOBLLd187HbE5ZeR62bzUnlN1wK1tphfgVa4ztmL+NY9nTgHMKki7LiNIL1p7M68=

@ -11,7 +11,7 @@ mkdir -p $HOME/<path_of_your_choice>/src
cd $HOME/<path_of_your_choice>/src
clone <harmony_repo>
git clone git@github.com:simple-rules/harmony-benchmark.git
```
## Usage
```

@ -6,8 +6,8 @@ import (
)
func TestBlockSerialize(t *testing.T) {
cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData)
if cbtx == nil || utxoPool == nil {
cbtx := NewCoinbaseTX("minh", genesisCoinbaseData)
if cbtx == nil {
t.Errorf("Failed to create a coinbase transaction.")
}
block := NewGenesisBlock(cbtx)

@ -161,13 +161,13 @@ func (bc *Blockchain) VerifyNewBlockAndUpdate(utxopool *UTXOPool, block *Block)
}
// CreateBlockchain creates a new blockchain DB
func CreateBlockchain(address string) (*Blockchain, *UTXOPool) {
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, utxoPool := NewCoinbaseTX(address, genesisCoinbaseData)
cbtx := NewCoinbaseTX(address, genesisCoinbaseData)
genesis := NewGenesisBlock(cbtx)
bc := Blockchain{[]*Block{genesis}}
return &bc, utxoPool
return &bc
}

@ -5,14 +5,14 @@ import (
)
func TestCreateBlockchain(t *testing.T) {
if bc, _ := CreateBlockchain("minh"); bc == nil {
if bc := CreateBlockchain("minh"); bc == nil {
t.Errorf("failed to create a blockchain")
}
}
func TestFindSpendableOutputs(t *testing.T) {
requestAmount := 3
bc, _ := CreateBlockchain("minh")
bc := CreateBlockchain("minh")
accumulated, unspentOutputs := bc.FindSpendableOutputs("minh", requestAmount)
if accumulated < DefaultCoinbaseValue {
t.Error("Failed to find enough unspent ouptuts")
@ -24,7 +24,7 @@ func TestFindSpendableOutputs(t *testing.T) {
}
func TestFindUTXO(t *testing.T) {
bc, _ := CreateBlockchain("minh")
bc := CreateBlockchain("minh")
utxo := bc.FindUTXO("minh")
total := 0
@ -41,7 +41,8 @@ func TestFindUTXO(t *testing.T) {
}
func TestAddNewUserTransfer(t *testing.T) {
bc, utxoPool := CreateBlockchain("minh")
bc := CreateBlockchain("minh")
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
if !bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) {
t.Error("Failed to add new transfer to alok.")
@ -57,7 +58,9 @@ func TestAddNewUserTransfer(t *testing.T) {
}
func TestVerifyNewBlock(t *testing.T) {
bc, utxoPool := CreateBlockchain("minh")
bc := CreateBlockchain("minh")
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3)
bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100)

@ -47,7 +47,7 @@ func (tx *Transaction) SetID() {
}
// NewCoinbaseTX creates a new coinbase transaction
func NewCoinbaseTX(to, data string) (*Transaction, *UTXOPool) {
func NewCoinbaseTX(to, data string) *Transaction {
if data == "" {
data = fmt.Sprintf("Reward to '%s'", to)
}
@ -56,14 +56,7 @@ func NewCoinbaseTX(to, data string) (*Transaction, *UTXOPool) {
txout := TXOutput{DefaultCoinbaseValue, to}
tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}}
tx.SetID()
txID := hex.EncodeToString(tx.ID)
var utxoPool UTXOPool
utxoPool.utxo = make(map[string]map[string]int)
utxoPool.utxo[to] = make(map[string]int)
utxoPool.utxo[to][txID] = DefaultCoinbaseValue
return &tx, &utxoPool
return &tx
}
// Used for debuging.

@ -5,7 +5,7 @@ import (
)
func TestNewCoinbaseTX(t *testing.T) {
if cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil || utxoPool == nil {
if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil {
t.Errorf("failed to create a coinbase transaction.")
}
}

@ -6,36 +6,38 @@ import (
// UTXOPool stores transactions and balance associated with each address.
type UTXOPool struct {
// Mapping from address to a map of transaction id to that balance.
// The assumption here is that one address only appears once output array in a transaction.
utxo map[string]map[string]int
// Mapping from address to a map of transaction id to a map of the index of output
// array in that transaction to that balance.
utxo map[string]map[string]map[int]int
}
// VerifyTransactions verifies if a list of transactions valid.
func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool {
spentTXOs := make(map[string]map[string]bool)
spentTXOs := make(map[string]map[string]map[int]bool)
if utxopool != nil {
for _, tx := range transactions {
inTotal := 0
// Calculate the sum of TxInput
for _, in := range tx.TxInput {
inTxID := hex.EncodeToString(in.TxID)
index := in.TxOutputIndex
// Check if the transaction with the addres is spent or not.
if val, ok := spentTXOs[in.Address][inTxID]; ok {
if val, ok := spentTXOs[in.Address][inTxID][index]; ok {
if val {
return false
}
}
// Mark the transactions with the addres spent.
if _, ok := spentTXOs[in.Address]; ok {
spentTXOs[in.Address][inTxID] = true
} else {
spentTXOs[in.Address] = make(map[string]bool)
spentTXOs[in.Address][inTxID] = true
// Mark the transactions with the address and index spent.
if _, ok := spentTXOs[in.Address]; !ok {
spentTXOs[in.Address] = make(map[string]map[int]bool)
}
if _, ok := spentTXOs[in.Address][inTxID]; !ok {
spentTXOs[in.Address][inTxID] = make(map[int]bool)
}
spentTXOs[in.Address][inTxID][index] = true
// Sum the balance up to the inTotal.
if val, ok := utxopool.utxo[in.Address][inTxID]; ok {
if val, ok := utxopool.utxo[in.Address][inTxID][index]; ok {
inTotal += val
} else {
return false
@ -73,18 +75,39 @@ func (utxopool *UTXOPool) Update(transactions []*Transaction) {
// Remove
for _, in := range tx.TxInput {
inTxID := hex.EncodeToString(in.TxID)
delete(utxopool.utxo[in.Address], inTxID)
delete(utxopool.utxo[in.Address][inTxID], in.TxOutputIndex)
}
// Update
for _, out := range tx.TxOutput {
if _, ok := utxopool.utxo[out.Address]; ok {
utxopool.utxo[out.Address][curTxID] = out.Value
} else {
utxopool.utxo[out.Address] = make(map[string]int)
utxopool.utxo[out.Address][curTxID] = out.Value
for index, out := range tx.TxOutput {
if _, ok := utxopool.utxo[out.Address]; !ok {
utxopool.utxo[out.Address] = make(map[string]map[int]int)
utxopool.utxo[out.Address][curTxID] = make(map[int]int)
}
if _, ok := utxopool.utxo[out.Address][curTxID]; !ok {
utxopool.utxo[out.Address][curTxID] = make(map[int]int)
}
utxopool.utxo[out.Address][curTxID][index] = out.Value
}
}
}
}
// CreateUTXOPoolFromTransaction a utxo pool from a genesis transaction.
func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool {
var utxoPool UTXOPool
txID := hex.EncodeToString(tx.ID)
utxoPool.utxo = make(map[string]map[string]map[int]int)
for index, out := range tx.TxOutput {
utxoPool.utxo[out.Address] = make(map[string]map[int]int)
utxoPool.utxo[out.Address][txID] = make(map[int]int)
utxoPool.utxo[out.Address][txID][index] = out.Value
}
return &utxoPool
}
// CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain.
func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool {
tx := bc.blocks[0].Transactions[0]
return CreateUTXOPoolFromTransaction(tx)
}

@ -5,7 +5,7 @@ import (
)
func TestVerifyTransactions(t *testing.T) {
if cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil || utxoPool == nil {
if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil {
t.Errorf("failed to create a coinbase transaction.")
}
}

@ -14,6 +14,7 @@ import (
var mutex = &sync.Mutex{}
// WaitForNewBlock waits for a new block.
func (consensus *Consensus) WaitForNewBlock(blockChannel chan blockchain.Block) {
for { // keep waiting for new blocks
newBlock := <-blockChannel
@ -24,7 +25,7 @@ func (consensus *Consensus) WaitForNewBlock(blockChannel chan blockchain.Block)
}
}
// Leader's consensus message dispatcher
// ProcessMessageLeader is the leader's consensus message dispatcher
func (consensus *Consensus) ProcessMessageLeader(message []byte) {
msgType, err := GetConsensusMessageType(message)
if err != nil {
@ -55,7 +56,7 @@ func (consensus *Consensus) ProcessMessageLeader(message []byte) {
// Handler for message which triggers consensus process
func (consensus *Consensus) processStartConsensusMessage(payload []byte) {
tx, _ := blockchain.NewCoinbaseTX("x", "y") // TODO: @minh, this fix is temporary to unblock the build. Please fix later.
tx := blockchain.NewCoinbaseTX("x", "y")
consensus.startConsensus(blockchain.NewGenesisBlock(tx))
}

Loading…
Cancel
Save