Merge branch 'master' into leveldb

pull/61/head
Minh Doan 6 years ago
commit 8c49e4996f
  1. 3
      agent/main.go
  2. 52
      aws-experiment-launch/experiment/commander/main.go
  3. 18
      blockchain/blockchain.go
  4. 29
      blockchain/blockchain_test.go
  5. 18
      blockchain/transaction.go
  6. 14
      blockchain/utxopool.go
  7. 16
      blockchain/utxopool_test.go
  8. 36
      client/txgen/main.go
  9. 12
      client/utils.go
  10. 4
      configr/main.go
  11. 2
      consensus/consensus.go
  12. 4
      consensus/consensus_leader_test.go
  13. 9
      crypto/pki/utils.go
  14. 155
      db/db.go
  15. 2
      kill_node.sh
  16. 4
      node/node.go
  17. 2
      node/node_utils.go
  18. 24
      run_experiment.sh

@ -27,7 +27,6 @@ func logMemUsage() {
}
}
// TODO: @ricl, start another process for reporting.
func logCPUUsage() {
p, _ := process.NewProcess(pid)
for {
@ -37,6 +36,7 @@ func logCPUUsage() {
time.Sleep(3 * time.Second)
}
}
func main() {
_ip := flag.String("ip", "127.0.0.1", "IP of the node")
_port := flag.String("port", "9000", "port of the node.")
@ -45,7 +45,6 @@ func main() {
logFolder := flag.String("log_folder", "latest", "the folder collecting the logs of this execution")
flag.Parse()
fmt.Print(*configFile)
ip = *_ip
port = *_port
pid = int32(*_pid)

@ -1,3 +1,16 @@
/*
Commander has two modes to setup configuration: Local and S3.
Local Config Mode
The Default Mode.
Add `-mode local` or omit `-mode` to enter local config mode. In this mode, the `commander` will host the config file `config.txt` on the commander machine and `solider`s will download the config file from `http://{commander_ip}:{commander_port}/distribution_config.txt`.
Remote Config Mode
Add `-mode remote` to enter remote config mode. In this mode, the `soldier`s will download the config file from a remote URL (use `-config_url {url}` to set the URL).
*/
package main
import (
@ -17,10 +30,13 @@ import (
)
type commanderSetting struct {
ip string
port string
ip string
port string
mode string
// Options in s3 mode
configURL string
configs [][]string
configs [][]string
}
type sessionInfo struct {
@ -35,13 +51,10 @@ var (
const (
DistributionFileName = "distribution_config.txt"
DefaultConfigUrl = "https://s3-us-west-2.amazonaws.com/unique-bucket-bin/distribution_config.txt"
)
func readConfigFile() [][]string {
if err := utils.DownloadFile(DistributionFileName, setting.configURL); err != nil {
panic(err)
}
if result, err := configr.ReadConfigFile(DistributionFileName); err != nil {
panic(err)
} else {
@ -57,6 +70,13 @@ func handleCommand(command string) {
switch cmd := args[0]; cmd {
case "config":
if setting.mode == "s3" {
// In s3 mode, download the config file from configURL first.
if err := utils.DownloadFile(DistributionFileName, setting.configURL); err != nil {
panic(err)
}
}
setting.configs = readConfigFile()
if setting.configs != nil {
log.Printf("The loaded config has %v nodes\n", len(setting.configs))
@ -82,10 +102,15 @@ func handleCommand(command string) {
}
}
func config(ip string, port string, configURL string) {
func config(ip string, port string, mode string, configURL string) {
setting.ip = ip
setting.port = port
setting.configURL = configURL
setting.mode = mode
if mode == "local" {
setting.configURL = fmt.Sprintf("http://%s:%s/%s", ip, port, DistributionFileName)
} else {
setting.configURL = configURL
}
}
func dictateNodes(command string) {
@ -181,6 +206,10 @@ func jsonResponse(w http.ResponseWriter, code int, message string) {
}
func serve() {
if setting.mode == "local" {
// Only host config file if in local mode
http.Handle("/", http.FileServer(http.Dir("./")))
}
http.HandleFunc("/upload", handleUploadRequest)
err := http.ListenAndServe(":"+setting.port, nil)
if err != nil {
@ -192,10 +221,11 @@ func serve() {
func main() {
ip := flag.String("ip", "127.0.0.1", "The ip of commander, i.e. this machine")
port := flag.String("port", "8080", "The port which the commander uses to communicate with soldiers")
configURL := flag.String("config_url", "https://s3-us-west-2.amazonaws.com/unique-bucket-bin/distribution_config.txt", "The config URL")
mode := flag.String("mode", "local", "The config mode, local or s3")
configURL := flag.String("config_url", DefaultConfigUrl, "The config URL")
flag.Parse()
config(*ip, *port, *configURL)
config(*ip, *port, *mode, *configURL)
go serve()

@ -3,6 +3,8 @@ package blockchain
import (
"bytes"
"encoding/hex"
"github.com/dedis/kyber"
"github.com/simple-rules/harmony-benchmark/crypto/pki"
)
// Blockchain keeps a sequence of Blocks
@ -103,7 +105,7 @@ Work:
}
// NewUTXOTransaction creates a new transaction
func (bc *Blockchain) NewUTXOTransaction(from, to [20]byte, amount int, shardID uint32) *Transaction {
func (bc *Blockchain) NewUTXOTransaction(priKey kyber.Scalar, from, to [20]byte, amount int, shardID uint32) *Transaction {
var inputs []TXInput
var outputs []TXOutput
@ -137,13 +139,23 @@ func (bc *Blockchain) NewUTXOTransaction(from, to [20]byte, amount int, shardID
tx := Transaction{ID: [32]byte{}, TxInput: inputs, TxOutput: outputs, Proofs: nil}
tx.SetID()
pubKey := pki.GetPublicKeyFromScalar(priKey)
bytes, err := pubKey.MarshalBinary()
if err == nil {
copy(tx.PublicKey[:], bytes)
} else {
panic("Failed to serialize public key")
}
tx.SetID() // TODO(RJ): figure out the correct way to set Tx ID.
tx.Sign(priKey)
return &tx
}
// AddNewUserTransfer creates a new transaction and a block of that transaction.
// Mostly used for testing.
func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, from, to [20]byte, amount int, shardId uint32) bool {
tx := bc.NewUTXOTransaction(from, to, amount, shardId)
func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, priKey kyber.Scalar, from, to [20]byte, amount int, shardId uint32) bool {
tx := bc.NewUTXOTransaction(priKey, from, to, amount, shardId)
if tx != nil {
newBlock := NewBlock([]*Transaction{tx}, bc.Blocks[len(bc.Blocks)-1].Hash, shardId)
if bc.VerifyNewBlockAndUpdate(utxoPool, newBlock) {

@ -1,14 +1,23 @@
package blockchain
import (
"github.com/simple-rules/harmony-benchmark/crypto/pki"
"testing"
)
var (
TestAddressOne = [20]byte{1}
TestAddressTwo = [20]byte{2}
TestAddressThree = [20]byte{3}
TestAddressFour = [20]byte{4}
PriIntOne = 111
PriIntTwo = 2
PriIntThree = 3
PriIntFour = 4
PriKeyOne = pki.GetPrivateKeyFromInt(PriIntOne)
PriKeyTwo = pki.GetPrivateKeyFromInt(PriIntTwo)
PriKeyThree = pki.GetPrivateKeyFromInt(PriIntThree)
PriKeyFour = pki.GetPrivateKeyFromInt(PriIntFour)
TestAddressOne = pki.GetAddressFromInt(PriIntOne)
TestAddressTwo = pki.GetAddressFromInt(PriIntTwo)
TestAddressThree = pki.GetAddressFromInt(PriIntThree)
TestAddressFour = pki.GetAddressFromInt(PriIntFour)
)
func TestCreateBlockchain(t *testing.T) {
@ -51,15 +60,15 @@ func TestAddNewUserTransfer(t *testing.T) {
bc := CreateBlockchain(TestAddressOne, 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
if !bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressThree, 3, 0) {
if !bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) {
t.Error("Failed to add new transfer to alok.")
}
if !bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressTwo, 100, 0) {
if !bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0) {
t.Error("Failed to add new transfer to rj.")
}
if bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressFour, DefaultCoinbaseValue-102, 0) {
if bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressFour, DefaultCoinbaseValue-102, 0) {
t.Error("minh should not have enough fun to make the transfer.")
}
}
@ -68,10 +77,10 @@ func TestVerifyNewBlock(t *testing.T) {
bc := CreateBlockchain(TestAddressOne, 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressTwo, 100, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0)
tx := bc.NewUTXOTransaction(TestAddressOne, TestAddressFour, 10, 0)
tx := bc.NewUTXOTransaction(PriKeyOne, TestAddressOne, TestAddressFour, 10, 0)
if tx == nil {
t.Error("failed to create a new transaction.")
}

@ -24,6 +24,7 @@ type Transaction struct {
ID [32]byte // 32 byte hash
TxInput []TXInput
TxOutput []TXOutput
PublicKey [32]byte
Signature [64]byte
Proofs []CrossShardTxProof // The proofs for crossShard tx unlock-to-commit/abort
@ -115,10 +116,27 @@ func (tx *Transaction) Sign(priKey kyber.Scalar) error {
log.Panic(err)
}
signature, err := schnorr.Sign(crypto.Ed25519Curve, priKey, encoded.Bytes())
if err != nil {
log.Panic(err)
}
copy(tx.Signature[:], signature)
return err
}
func (tx *Transaction) GetContentToVerify() []byte {
tempTx := *tx
tempTx.Signature = [64]byte{}
var encoded bytes.Buffer
enc := gob.NewEncoder(&encoded)
err := enc.Encode(tempTx)
if err != nil {
log.Panic(err)
}
return encoded.Bytes()
}
// NewCoinbaseTX creates a new coinbase transaction
func NewCoinbaseTX(toAddress [20]byte, data string, shardID uint32) *Transaction {
if data == "" {

@ -5,6 +5,9 @@ import (
"encoding/gob"
"encoding/hex"
"fmt"
"github.com/dedis/kyber/sign/schnorr"
"github.com/simple-rules/harmony-benchmark/crypto"
"github.com/simple-rules/harmony-benchmark/log"
"sync"
)
@ -108,6 +111,17 @@ func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[[
return false, false // Here crossShard is false, because if there is no business for this shard, it's effectively not crossShard no matter what.
}
// Verify the signature
pubKey := crypto.Ed25519Curve.Point()
err := pubKey.UnmarshalBinary(tx.PublicKey[:])
if err != nil {
log.Error("Failed to deserialize public key", "error", err)
}
err = schnorr.Verify(crypto.Ed25519Curve, pubKey, tx.GetContentToVerify(), tx.Signature[:])
if err != nil {
log.Error("Failed to verify signature", "error", err, "public key", pubKey, "pubKey in bytes", tx.PublicKey[:])
return false, crossShard
}
return true, crossShard
}

@ -8,10 +8,10 @@ func TestVerifyOneTransactionAndUpdate(t *testing.T) {
bc := CreateBlockchain(TestAddressOne, 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressTwo, 100, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0)
tx := bc.NewUTXOTransaction(TestAddressOne, TestAddressFour, 10, 0)
tx := bc.NewUTXOTransaction(PriKeyOne, TestAddressOne, TestAddressFour, 10, 0)
if tx == nil {
t.Error("failed to create a new transaction.")
}
@ -26,10 +26,10 @@ func TestVerifyOneTransactionFail(t *testing.T) {
bc := CreateBlockchain(TestAddressOne, 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressTwo, 100, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0)
tx := bc.NewUTXOTransaction(TestAddressOne, TestAddressFour, 10, 0)
tx := bc.NewUTXOTransaction(PriKeyOne, TestAddressOne, TestAddressFour, 10, 0)
if tx == nil {
t.Error("failed to create a new transaction.")
}
@ -44,8 +44,8 @@ func TestDeleteOneBalanceItem(t *testing.T) {
bc := CreateBlockchain(TestAddressOne, 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, TestAddressThree, TestAddressTwo, 3, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0)
bc.AddNewUserTransfer(utxoPool, PriKeyThree, TestAddressThree, TestAddressTwo, 3, 0)
if _, ok := utxoPool.UtxoMap[TestAddressThree]; ok {
t.Errorf("alok should not be contained in the balance map")

@ -164,23 +164,32 @@ func generateCrossShardTx(txInfo *TxInfo) {
}
// Spend the utxo from the current shard to a random address in [0 - N)
txout := blockchain.TXOutput{txInfo.value, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress)), nodeShardID}
txout := blockchain.TXOutput{txInfo.value, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress) + 1), nodeShardID}
txOutputs := []blockchain.TXOutput{txout}
// Spend the utxo from the other shard, if any, to a random address in [0 - N)
if crossTxin != nil {
crossTxout := blockchain.TXOutput{crossUtxoValue, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress)), uint32(crossShardId)}
crossTxout := blockchain.TXOutput{crossUtxoValue, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress) + 1), uint32(crossShardId)}
txOutputs = append(txOutputs, crossTxout)
}
// Construct the new transaction
tx := blockchain.Transaction{ID: [32]byte{}, TxInput: txInputs, TxOutput: txOutputs, Proofs: nil}
tx.SetID()
priKeyInt, ok := client.AddressToIntPriKeyMap[txInfo.address]
priKeyInt, ok := client.LookUpIntPriKey(txInfo.address)
if ok {
bytes, err := pki.GetPublicKeyFromScalar(pki.GetPrivateKeyFromInt(priKeyInt)).MarshalBinary()
if err == nil {
copy(tx.PublicKey[:], bytes)
} else {
log.Error("Failed to serialized public key", "error", err)
return
}
tx.SetID() // TODO(RJ): figure out the correct way to set Tx ID.
tx.Sign(pki.GetPrivateKeyFromInt(priKeyInt))
} else {
panic("Failed to look up the corresponding private key from address")
log.Error("Failed to look up the corresponding private key from address", "Address", txInfo.address)
return
}
txInfo.crossTxs = append(txInfo.crossTxs, &tx)
@ -193,14 +202,23 @@ func generateSingleShardTx(txInfo *TxInfo) {
txin := blockchain.NewTXInput(blockchain.NewOutPoint(&txInfo.id, txInfo.index), txInfo.address, nodeShardID)
// Spend the utxo to a random address in [0 - N)
txout := blockchain.TXOutput{txInfo.value, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress)), nodeShardID}
txout := blockchain.TXOutput{txInfo.value, pki.GetAddressFromInt(rand.Intn(setting.numOfAddress) + 1), nodeShardID}
tx := blockchain.Transaction{ID: [32]byte{}, TxInput: []blockchain.TXInput{*txin}, TxOutput: []blockchain.TXOutput{txout}, Proofs: nil}
tx.SetID() // TODO(RJ): figure out the correct way to set Tx ID.
priKeyInt, ok := client.AddressToIntPriKeyMap[txInfo.address]
priKeyInt, ok := client.LookUpIntPriKey(txInfo.address)
if ok {
bytes, err := pki.GetPublicKeyFromScalar(pki.GetPrivateKeyFromInt(priKeyInt)).MarshalBinary()
if err == nil {
copy(tx.PublicKey[:], bytes)
} else {
log.Error("Failed to serialized public key", "error", err)
return
}
tx.SetID() // TODO(RJ): figure out the correct way to set Tx ID.
tx.Sign(pki.GetPrivateKeyFromInt(priKeyInt))
} else {
panic("Failed to look up the corresponding private key from address")
log.Error("Failed to look up the corresponding private key from address", "Address", txInfo.address)
return
}
txInfo.txs = append(txInfo.txs, &tx)

@ -4,9 +4,13 @@ import "github.com/simple-rules/harmony-benchmark/crypto/pki"
var AddressToIntPriKeyMap map[[20]byte]int // For convenience, we use int as the secret seed for generating private key
func init() {
AddressToIntPriKeyMap := make(map[[20]byte]int)
for i := 0; i < 10000; i++ {
AddressToIntPriKeyMap[pki.GetAddressFromInt(i)] = i
func LookUpIntPriKey(address [20]byte) (int, bool) {
if AddressToIntPriKeyMap == nil {
AddressToIntPriKeyMap = make(map[[20]byte]int)
for i := 1; i <= 10000; i++ {
AddressToIntPriKeyMap[pki.GetAddressFromInt(i)] = i
}
}
value, ok := AddressToIntPriKeyMap[address]
return value, ok
}

@ -94,7 +94,7 @@ func GetPeers(myIp, myPort, myShardId string, config *[][]string) []p2p.Peer {
// Get public key deterministically based on ip and port
peer := p2p.Peer{Port: port, Ip: ip}
priKey := crypto.Ed25519Curve.Scalar().SetInt64(int64(utils.GetUniqueIdFromPeer(peer)))
peer.PubKey = pki.GetPublicKeyFromScalar(crypto.Ed25519Curve, priKey)
peer.PubKey = pki.GetPublicKeyFromScalar(priKey)
peerList = append(peerList, peer)
}
return peerList
@ -111,7 +111,7 @@ func GetLeader(myShardId string, config *[][]string) p2p.Peer {
// Get public key deterministically based on ip and port
priKey := crypto.Ed25519Curve.Scalar().SetInt64(int64(utils.GetUniqueIdFromPeer(leaderPeer))) // TODO: figure out why using a random hash value doesn't work for private key (schnorr)
leaderPeer.PubKey = pki.GetPublicKeyFromScalar(crypto.Ed25519Curve, priKey)
leaderPeer.PubKey = pki.GetPublicKeyFromScalar(priKey)
}
}
return leaderPeer

@ -118,7 +118,7 @@ func NewConsensus(ip, port, ShardID string, peers []p2p.Peer, leader p2p.Peer) *
// Set private key for myself so that I can sign messages.
consensus.priKey = crypto.Ed25519Curve.Scalar().SetInt64(int64(consensus.nodeId))
consensus.pubKey = pki.GetPublicKeyFromScalar(crypto.Ed25519Curve, consensus.priKey)
consensus.pubKey = pki.GetPublicKeyFromScalar(consensus.priKey)
consensus.consensusId = 0 // or view Id in the original pbft paper
myShardID, err := strconv.Atoi(ShardID)

@ -25,13 +25,13 @@ func TestConstructChallengeMessage(test *testing.T) {
leaderPriKey := crypto.Ed25519Curve.Scalar()
priKeyInBytes := crypto.HashSha256("12")
leaderPriKey.UnmarshalBinary(priKeyInBytes[:])
leaderPubKey := pki.GetPublicKeyFromScalar(crypto.Ed25519Curve, leaderPriKey)
leaderPubKey := pki.GetPublicKeyFromScalar(leaderPriKey)
leader := p2p.Peer{Ip: "1", Port: "2", PubKey: leaderPubKey}
validatorPriKey := crypto.Ed25519Curve.Scalar()
priKeyInBytes = crypto.HashSha256("12")
validatorPriKey.UnmarshalBinary(priKeyInBytes[:])
validatorPubKey := pki.GetPublicKeyFromScalar(crypto.Ed25519Curve, leaderPriKey)
validatorPubKey := pki.GetPublicKeyFromScalar(leaderPriKey)
validator := p2p.Peer{Ip: "3", Port: "5", PubKey: validatorPubKey}
consensus := NewConsensus("1", "2", "0", []p2p.Peer{leader, validator}, leader)

@ -20,20 +20,21 @@ func GetAddressFromPublicKey(pubKey kyber.Point) [20]byte {
// Temporary helper function for benchmark use
func GetAddressFromInt(value int) [20]byte {
return GetAddressFromPublicKey(GetPublicKeyFromScalar(crypto.Ed25519Curve, GetPrivateKeyFromInt(value)))
return GetAddressFromPublicKey(GetPublicKeyFromScalar(GetPrivateKeyFromInt(value)))
}
func GetPrivateKeyFromInt(value int) kyber.Scalar {
return crypto.Ed25519Curve.Scalar().SetInt64(int64(value))
}
func GetPublicKeyFromPrivateKey(suite crypto.Suite, priKey [32]byte) kyber.Point {
func GetPublicKeyFromPrivateKey(priKey [32]byte) kyber.Point {
suite := crypto.Ed25519Curve
scalar := suite.Scalar()
scalar.UnmarshalBinary(priKey[:])
return suite.Point().Mul(scalar, nil)
}
// Same as GetPublicKeyFromPrivateKey, but it directly works on kyber.Scalar object.
func GetPublicKeyFromScalar(suite crypto.Suite, priKey kyber.Scalar) kyber.Point {
return suite.Point().Mul(priKey, nil)
func GetPublicKeyFromScalar(priKey kyber.Scalar) kyber.Point {
return crypto.Ed25519Curve.Point().Mul(priKey, nil)
}

@ -1,9 +1,6 @@
package db
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
@ -128,157 +125,7 @@ func (db *LDBDatabase) LDB() *leveldb.DB {
return db.db
}
// meter periodically retrieves internal leveldb counters and reports them to
// the metrics subsystem.
//
// This is how a stats table look like (currently):
// Compactions
// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
// -------+------------+---------------+---------------+---------------+---------------
// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
//
// This is how the write delay look like (currently):
// DelayN:5 Delay:406.604657ms Paused: false
//
// This is how the iostats look like (currently):
// Read(MB):3895.04860 Write(MB):3654.64712
func (db *LDBDatabase) meter(refresh time.Duration) {
// Create the counters to store current and previous compaction values
compactions := make([][]float64, 2)
for i := 0; i < 2; i++ {
compactions[i] = make([]float64, 3)
}
// Create storage for iostats.
var iostats [2]float64
// Create storage and warning log tracer for write delay.
var (
delaystats [2]int64
lastWritePaused time.Time
)
var (
errc chan error
merr error
)
// Iterate ad infinitum and collect the stats
for i := 1; errc == nil && merr == nil; i++ {
// Retrieve the database stats
stats, err := db.db.GetProperty("leveldb.stats")
if err != nil {
db.log.Error("Failed to read database stats", "err", err)
merr = err
continue
}
// Find the compaction table, skip the header
lines := strings.Split(stats, "\n")
for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" {
lines = lines[1:]
}
if len(lines) <= 3 {
db.log.Error("Compaction table not found")
merr = errors.New("compaction table not found")
continue
}
lines = lines[3:]
// Iterate over all the table rows, and accumulate the entries
for j := 0; j < len(compactions[i%2]); j++ {
compactions[i%2][j] = 0
}
for _, line := range lines {
parts := strings.Split(line, "|")
if len(parts) != 6 {
break
}
for idx, counter := range parts[3:] {
value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
if err != nil {
db.log.Error("Compaction entry parsing failed", "err", err)
merr = err
continue
}
compactions[i%2][idx] += value
}
}
// Retrieve the write delay statistic
writedelay, err := db.db.GetProperty("leveldb.writedelay")
if err != nil {
db.log.Error("Failed to read database write delay statistic", "err", err)
merr = err
continue
}
var (
delayN int64
delayDuration string
duration time.Duration
paused bool
)
if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil {
db.log.Error("Write delay statistic not found")
merr = err
continue
}
duration, err = time.ParseDuration(delayDuration)
if err != nil {
db.log.Error("Failed to parse delay duration", "err", err)
merr = err
continue
}
// If a warning that db is performing compaction has been displayed, any subsequent
// warnings will be withheld for one minute not to overwhelm the user.
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) {
db.log.Warn("Database compacting, degraded performance")
lastWritePaused = time.Now()
}
delaystats[0], delaystats[1] = delayN, duration.Nanoseconds()
// Retrieve the database iostats.
ioStats, err := db.db.GetProperty("leveldb.iostats")
if err != nil {
db.log.Error("Failed to read database iostats", "err", err)
merr = err
continue
}
var nRead, nWrite float64
parts := strings.Split(ioStats, " ")
if len(parts) < 2 {
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
merr = fmt.Errorf("bad syntax of ioStats %s", ioStats)
continue
}
if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil {
db.log.Error("Bad syntax of read entry", "entry", parts[0])
merr = err
continue
}
if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil {
db.log.Error("Bad syntax of write entry", "entry", parts[1])
merr = err
continue
}
iostats[0], iostats[1] = nRead, nWrite
// Sleep a bit, then repeat the stats collection
select {
case errc = <-db.quitChan:
// Quit requesting, stop hammering the database
case <-time.After(refresh):
// Timeout, gather a new set of stats
}
}
if errc == nil {
errc = <-db.quitChan
}
errc <- merr
}
// TODO(minhdoan): Might add meter func from ethereum-go repo
func (db *LDBDatabase) NewBatch() Batch {
return &ldbBatch{db: db.db, b: new(leveldb.Batch)}

@ -1,4 +1,4 @@
for pid in `/bin/ps -fu $USER| grep "benchmark\|txgen" | grep -v "grep" | awk '{print $2}'`;
for pid in `/bin/ps -fu $USER| grep "benchmark\|txgen\|soldier\|commander" | grep -v "grep" | awk '{print $2}'`;
do
echo 'Killed process: '$pid
kill -9 $pid

@ -8,6 +8,7 @@ import (
"github.com/simple-rules/harmony-benchmark/blockchain"
"github.com/simple-rules/harmony-benchmark/client"
"github.com/simple-rules/harmony-benchmark/consensus"
"github.com/simple-rules/harmony-benchmark/crypto/pki"
"github.com/simple-rules/harmony-benchmark/log"
"github.com/simple-rules/harmony-benchmark/p2p"
)
@ -105,7 +106,8 @@ func New(consensus *consensus.Consensus) *Node {
// TODO(minh): Use or implement new function in blockchain package for this.
genesisBlock := &blockchain.Blockchain{}
genesisBlock.Blocks = make([]*blockchain.Block, 0)
coinbaseTx := blockchain.NewCoinbaseTX([20]byte{0}, "0", node.Consensus.ShardID)
// TODO(RJ): use miner's address as coinbase address
coinbaseTx := blockchain.NewCoinbaseTX(pki.GetAddressFromInt(1), "0", node.Consensus.ShardID)
genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx, node.Consensus.ShardID))
node.blockchain = genesisBlock

@ -11,7 +11,7 @@ import (
func (node *Node) AddTestingAddresses(numAddress int) {
txs := make([]*blockchain.Transaction, numAddress)
for i := range txs {
txs[i] = blockchain.NewCoinbaseTX(pki.GetAddressFromInt(i), "", node.Consensus.ShardID)
txs[i] = blockchain.NewCoinbaseTX(pki.GetAddressFromInt(i+1), "", node.Consensus.ShardID)
}
node.blockchain.Blocks[0].Transactions = append(node.blockchain.Blocks[0].Transactions, txs...)
node.UtxoPool.Update(txs)

@ -0,0 +1,24 @@
# Kill nodes if any
./kill_node.sh
go build -o bin/benchmark
go build -o bin/txgen client/txgen/main.go
go build -o bin/commander aws-experiment-launch/experiment/commander/main.go
go build -o bin/soldier aws-experiment-launch/experiment/soldier/main.go
cd bin
# Create a tmp folder for logs
t=`date +"%Y%m%d-%H%M%S"`
log_folder="tmp_log/log-$t"
mkdir -p $log_folder
# For each of the nodes, start soldier
config=distribution_config.txt
while IFS='' read -r line || [[ -n "$line" ]]; do
IFS=' ' read ip port mode shardId <<< $line
#echo $ip $port $mode
./soldier -ip $ip -port $port&
done < $config
./commander
Loading…
Cancel
Save