From 37d9680f1bc99c0a16339327b455ba34fe91567a Mon Sep 17 00:00:00 2001 From: Miguel Montes <miguel.montes@gmail.com> Date: Mon, 12 Nov 2018 08:19:12 -0300 Subject: [PATCH] Optimizaciones de bfa_client --- bfa_client/src/client/bfa_client.go | 255 +++++++++++++++++++++++----- 1 file changed, 215 insertions(+), 40 deletions(-) diff --git a/bfa_client/src/client/bfa_client.go b/bfa_client/src/client/bfa_client.go index c520854..86e5d7c 100644 --- a/bfa_client/src/client/bfa_client.go +++ b/bfa_client/src/client/bfa_client.go @@ -14,6 +14,7 @@ import ( "log" "os" "path" + "runtime" "sort" "strconv" "strings" @@ -63,15 +64,13 @@ func getSigner(header *types.Header) (signer string, err error) { signature := header.Extra[len(header.Extra)-65:] hash := sigHash(header).Bytes() pubkey, err := crypto.Ecrecover(hash, signature) - address := make([]byte,20) + address := make([]byte, 20) copy(address, crypto.Keccak256(pubkey[1:])[12:]) signer = toHex(address) return } func (node *Node) getBlockSigner(blockNumber int64) (signer string) { - fmt.Printf("in getBlockSigner(%d)\n",blockNumber) - defer fmt.Printf("out getBlockSigner(%d)\n",blockNumber) header := node.getBlockByNumber(blockNumber) signer, err := getSigner(&header) check(err) @@ -119,7 +118,7 @@ func (node *Node) getSnapshotAtBlock(blockNumber int64) Snapshot { func (node *Node) getSigners() (signers []string) { var s []common.Address node.Call(&s, "clique_getSigners", nil) - for _, signer := range s{ + for _, signer := range s { signers = append(signers, toHex(signer.Bytes())) } return @@ -128,7 +127,7 @@ func (node *Node) getSigners() (signers []string) { func (node *Node) getSignersAtHash(hash common.Hash) (signers []string) { var s []common.Address node.Call(&signers, "clique_getSignersAtHash", hash) - for _, signer := range s{ + for _, signer := range s { signers = append(signers, toHex(signer.Bytes())) } return @@ -203,19 +202,22 @@ func (node *Node) sealersStatus() map[string]int64 { return status } +func printDebug(msg string) { + ptr, _, _, _ := runtime.Caller(1) + fmt.Printf("%v: %v\n", msg, runtime.FuncForPC(ptr).Name()) +} + func (node *Node) getSealerInception(address string) (since int64) { - fmt.Println("in getSealerInception") - defer fmt.Println("out getSealerInception") - if signers := node.getSigners(); !contains(signers, address){ + if signers := node.getSigners(); !contains(signers, address) { return -1 } lo := int64(0) hi := node.blockNumber() for lo < hi { - mid := lo + (hi - lo) / 2 + mid := lo + (hi-lo)/2 signers := node.getSignersAtBlock(mid) - if contains(signers, address){ + if contains(signers, address) { hi = mid } else { lo = mid + 1 @@ -224,28 +226,208 @@ func (node *Node) getSealerInception(address string) (since int64) { return hi } -func (node *Node) getSignerFirstBlock(signer string, since int64, until int64) (blockNumber int64){ - fmt.Println("in getSignerFirstBlock") - defer fmt.Println("out getSignerFirstBlock") - if since < 0{ +func min(a, b int64) int64 { + if a < b { + return a + } + return b +} + +func (node *Node) getSignerFirstBlock(signer string, since int64, until int64) (blockNumber int64) { + if since < 0 { return -1 } - for i := since; i <= until; i++ { - if signer == node.getBlockSigner(i){ - return i + //snapshot := node.getSnapshotAtBlock(since) + var count int64 = 20 + // first, we look close to the inception + if blockNumber = node.searchSnapshotForward(since, signer, count); blockNumber > 0 { + return + } + since += count + n := min(10, (until-since)/count+1) // number of goroutines + ch := make(chan int64) + for i := int64(0); i < n; i++ { + go func() { + for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch { + cnt := min(count, until-blockNumber+1) + if found := node.searchSnapshotForward(blockNumber, signer, cnt); found > 0 { + ch <- found + } + } + ch <- (-1) + }() + } + for { + select { + case ch <- since: + switch { + case since < 0: + continue + case since + count < until: + since += count + default: + since = -1 //we have exhausted the search space + } + case found := <-ch: + switch { + case found < 0: + n-- // a goroutine has ended + if n == 0 { // all goroutines have ended + return + } + case blockNumber < 0: + blockNumber = found // first time we see this signer + since = -1 // Notify everyone + case found < blockNumber: + blockNumber = found // found an earlier block + } + } + } +} + +func (node *Node) getSignerFirstBlock_(signer string, since int64, until int64) (blockNumber int64) { + if since < 0 { + return -1 + } + last := since + for i := since; ; { + snapshot := node.getSnapshotAtBlock(i) + n := int64(len(snapshot.Recents)) + if int64(snapshot.Number)-n > last { + i-- + continue + } + for b, s := range snapshot.Recents { + if toHex(s[:]) == signer { + return int64(b) + } + } + if i >= until { + return -1 + } + last = i + i += n + } +} + +func (node *Node) searchSnapshot(blockNumber int64, signer string, count int64, forward bool) (found int64) { + found = -1 + for count > 0 { + snapshot := node.getSnapshotAtBlock(blockNumber + count - 1) + for b, s := range snapshot.Recents { + if toHex(s[:]) == signer { + found = int64(b) + if !forward { + return + } + } } + count -= int64(len(snapshot.Recents)) + } + return +} + +func (node *Node) searchSnapshotForward(blockNumber int64, signer string, count int64) (found int64) { + found = -1 + for count > 0 { + snapshot := node.getSnapshotAtBlock(blockNumber + count - 1) + for b, s := range snapshot.Recents { + if toHex(s[:]) == signer { + found = int64(b) + } + } + count -= int64(len(snapshot.Recents)) + } + return +} + +func (node *Node) searchSnapshotBackward(blockNumber int64, signer string, count int64) (found int64) { + found = -1 + for i := int64(0); i < count; { + snapshot := node.getSnapshotAtBlock(blockNumber - i) + for b, s := range snapshot.Recents { + if toHex(s[:]) == signer { + return int64(b) + } + } + i += int64(len(snapshot.Recents)) + } + return +} + +func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (blockNumber int64) { + if since < 0 { + return -1 + } + var count int64 = 20 + // first, we look close to the last block + if blockNumber = node.searchSnapshotBackward(until, signer, count); blockNumber > 0 { + return + } + until -= count + n := min(10, (until-since)/count+1) // number of goroutines + ch := make(chan int64) + for i := int64(0); i < n; i++ { + go func() { + for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch { + cnt := min(count, blockNumber - since + 1) + if found := node.searchSnapshotBackward(blockNumber, signer, cnt); found > 0 { + ch <- found + } + } + ch <- (-1) + }() + } + for { + select { + case ch <- since: + switch { + case until < 0: + continue + case until - count > since: + until -= count + default: + until = -1 //we have exhausted the search space + } + case found := <-ch: + switch { + case found < 0: + n-- // a goroutine has ended + if n == 0 { // all goroutines have ended + return + } + case blockNumber < 0: + blockNumber = found // first time we see this signer + until = -1 // Notify everyone + case found > blockNumber: + blockNumber = found // found a later block + } + } + } +} + +func (node *Node) getSignerLastBlock__(signer string, since int64, until int64) (blockNumber int64) { + if since < 0 { + return -1 + } + for i := until; i >= since; { + snapshot := node.getSnapshotAtBlock(i) + for b, s := range snapshot.Recents { + if toHex(s[:]) == signer { + return int64(b) + } + } + i -= int64(len(snapshot.Recents)) } return -1 } -func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (blockNumber int64){ - fmt.Println("in getSignerLastBlock") - defer fmt.Println("out getSignerLastBlock") +func (node *Node) getSignerLastBlock_(signer string, since int64, until int64) (blockNumber int64) { if since < 0 { return -1 } for i := until; i >= since; i-- { - if signer == node.getBlockSigner(i){ + if signer == node.getBlockSigner(i) { return i } } @@ -253,25 +435,22 @@ func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (b } type SealerInfo struct { - Address string + Address string CurrentBlock int64 - Since int64 - FirstBlock int64 - LastBlock int64 + Since int64 + FirstBlock int64 + LastBlock int64 } - func (node *Node) sealerInfo(sealer string) (info SealerInfo, err error) { - fmt.Println("in sealerInfo") - defer fmt.Println("out sealerInfo") info.Address = sealer info.CurrentBlock = node.blockNumber() info.Since = node.getSealerInception(sealer) if info.Since == -1 { return info, fmt.Errorf("%q is not a sealer", sealer) } - info.FirstBlock = node.getSignerFirstBlock(sealer, info.Since+1, info.CurrentBlock ) - info.LastBlock = node.getSignerLastBlock(sealer,info.FirstBlock, info.CurrentBlock) + info.FirstBlock = node.getSignerFirstBlock(sealer, info.Since + 1, info.CurrentBlock) + info.LastBlock = node.getSignerLastBlock(sealer, info.FirstBlock, info.CurrentBlock) return } @@ -301,9 +480,7 @@ func printVotes(node *Node, useJson bool) { } } -func printSealerInfo(node *Node, sealer string){ - fmt.Println("in printSealerInfo") - defer fmt.Println("out printSealerInfo") +func printSealerInfo(node *Node, sealer string) { info, err := node.sealerInfo(sealer) check(err) v, err := json.MarshalIndent(info, "", " ") @@ -382,9 +559,9 @@ func main() { command = "" commands = []string{"sealers", "proposals", "sealerInfo"} desc = map[string]string{ - "proposals": "Detalla el estado de una votación", + "proposals": "Detalla el estado de una votación", "sealerInfo": "Brinda datos sobre un sealer", - "sealers": "Brinda información sobre la última actividad de los selladores", + "sealers": "Brinda información sobre la última actividad de los selladores", } ) defer func() { @@ -402,8 +579,8 @@ func main() { } flags.BoolVar(&useJson, "json", false, "Produce salida en formato json") flags.StringVar(&url, "url", DefaultURL, "URL para conexión con geth. Ejemplo: /home/bfa/bfa/network/node/geth.ipc") - flags.BoolVar(&help, "h", false, "") - flags.BoolVar(&help, "help", false, "Muestra esta ayuda") + //flags.BoolVar(&help, "h", false, "") + //flags.BoolVar(&help, "help", false, "Muestra esta ayuda") flags.Parse(os.Args[2:]) if help { fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones]\n%v\nOpciones: \n", path.Base(os.Args[0]), command, desc[command]) @@ -418,10 +595,8 @@ func main() { case "proposals": printVotes(node, useJson) case "sealerInfo": - fmt.Println(flags.NArg(), flags.Args()) for i := 0; i < flags.NArg(); i++ { - fmt.Println(flags.Arg(i)) - printSealerInfo(node,flags.Arg(i)) + printSealerInfo(node, flags.Arg(i)) } } } -- GitLab