Merge master to t3 0523 (#3085)

* fix signers share computation to use only non-harmony nodes (#3008)

* Add LastEpochInCommittee at prestaking epoch too (#3014)

* write validator stats at the end of prestaking epoch (#3021)

* write validator stats at the end of prestaking epoch

* also need to write block reward accumulator

* [build] enable static build by default (#2885)

scripts/go_executable_build.sh -s (static build, default)
scripts/go_executable_build.sh -S (non-static build)

Signed-off-by: Leo Chen <leo@harmony.one>

* Code formatting fix based on `staticcheck` (#3023)

* fix some static check issues

* more fixes according to staticcheck

* add nil check on getHeader

* Add more log info

* [rpc] Revert change to v2 GetBalance RPC (#3037)

* Cherrypick crosslink related fixes from t3 to master. (#3045)

* Optimize crosslink verification logic and add more cache (#3032)

* make crosslink broadcast smarter and more efficient (#3036)

* adjust catch up speed to be a sane number

* Fix crosslink broadcast condition (#3041)

* Tx pool error report fix & local build fix (#3046)

* [tx_list] Add transaction after you can fetch tx cost

* [tx_pool] Add error sink reports for removed tx

* Correct log levels for known transactions
* Remove redundant hash to `enqueue` and `add` signatures
* Update tests for signature changes

* [build] Fix local build for MacOs

* [tx_pool] Correct typo & logging level for known tx

* [config] Create Testnet config

* [node.sh] update testnet network config

* [config] correct testnet config

* [main] Enable beacon sync for explorer nodes (#3059)

* [apr] should not use snapshot from last epoch, use current epoch snapshot (#3051)

* use snapshot total delegation instead of current total delegation

* should not use snapshot from last epoch, use current epoch snapshot (#3049)

Co-authored-by: Rongjian Lan <rongjian.lan@gmail.com>

Co-authored-by: Rongjian Lan <rongjian.lan@gmail.com>

* cherrypick log level change

* [rpc] Add active status back to Validator information
[validator] Fix typo for ValidatorRPCEnhanced
[Makefile] Change make exe to build non-static by default

* [network] Added caching to node server (#3048)

* [network] Added caching to node server

* [network] renamed two singleflight.Group

* [network] added two error handling

* [network] added forget logic for single flight

* [network] changed single flight to lru cache solution

* [network] adjusted the cache size

* [network] changed cache size to 10000

* Transaction api improvements (#3057)

* [node] Add option to broadcast invalid tx (on by default)

* update main args to take in broadcast invalid tx
* update node.sh for new broadcast invalid tx option

* [rpc] Do not submit transaction if tx has been finalized

* Support legacy behavior and not return errors on tx submission

* [main] make broadcasting invalid tx default false

* [node] Fix formatting

* Add timeouts for the explorer HTTP service

* [test] State trans unit test (#3043)

* completing create-validator tests

generalizing create validator tests, started with edit validator tests

one round completed before major refactor

* [test] finished coding test TestCheckDuplicateFields

* [test] finished debug TestCheckDuplicateFields

* [test] Added TestDescription_EnsureLength

* [test] added test in validator_test.go TestUpdateDescription

* [test] Added test TestComputed_String

* [test] refactored TestValidatorSanityCheck and added some message in error message returned from sanity check

* [test] removed test index for debugging

* [test] Added test TestValidatorWrapper_SanityCheck. Added value check for TestMarshalUnmarshalValidator. Fixed rlp usage defect in UnmarshalValidator

* [test] added test TestVerifyBLSKeys

* [test] added test TestContainsHarmonyBLSKeys

* [test] added test TestCreateValidatorFromNewMsg

* [test] fixed some tests errors

* [test] added test TestUpdateValidatorFromEditMsg, last editted the test file, finished testing validator_test.go

* [staking] added numeric.Dec.Copy method

* [staking] added CommissionRates.Copy

* [staking] add nil case handle to copy method and related test case

* [test] added nil case for commissionRates.Copy test

* [staking] finished CreateValidator.Copy and related test case

* [staking] added EditValidator.Copy method and related test case

* [test] added zero test cases for Copy method

* [staking] implemented Delegate.Copy and related unit test case

* [staking] added Undelegate.Copy and CollectReward.Copy method. Implemented corresponding test cases

* [test] added two more simple unit tests

* [test] solving the merge conflict with deep copy fix

* [test] added schedule for sharding

* [test] refactored double_sign_test.go

* [test] comment out all test cases for now.

* [test] added record Copy method for testing

* [test] added the first test case in TestVerify

* [test] finished test TestVerify

* [test] Added test TestVerify, TestApplySlashRate, TestSetDifference

* [test] half through TestDelegatorSlashApply

* [test] fix the problem cause by unsafe usage of big.Int

* [staking] added the copy methods to validatorWrapper

* [test] added test cases for copy method for staking/validatorWrapper

* [test] added test case TestApply

* [test] added test case TestRate

* [test] fix the golint errors

* [test] removed commented out unit test code

* [test] remote the empty line in imports

* [test] moved copy methods to stake_testing module

* [test] removed usage of interface stateDB

* [test] removed empty lines in imports

* [test] fixed golint package name issues

* [test] removed a todo when writing code

* [test] moved record.Copy to staking/slash/test

* [test] add some changes

* [test] added prototypes in staketest module

* [test] fix the golint issue in staketest

* [test] make prototype more beautiful

* [test] refactored test TestCheckDuplicateFields

* [test] add createValidator test data

* [test] added positive test case for VerifyAndCreateValidatorFromMsg

* [test] added create validator test

* [test] added the positive test case for TestVerifyAndEditValidatorFromMsg

* [test] added the tests case TestVerifyAndEditValidatorFromMsg

* [test] fix one of the error is not triggered as expected

* [test] more changes in test

* [test] fix the positive test data for TestVerifyAndDelegateFromMsg

* [test] Fixed two comment golint errors

* [test] added delegate tests

* [test] added a make function. WIP

* [test] added undelegate positive test

* [test] added negative test cases for undelegate

* [test] added positive test. not passed. Need to add assert method in test suites

* [test] added equal function to check Validator Equality

* [test] added equals for staketest

* [test] replaced deep equal with new equal methods:

* [test] removed unused codes

* [test] Finishing touch

* [test] fix comment golint issue

* [test] removed dead code in staking_verifier_test.go

Co-authored-by: Ganesha Upadhyaya <ganeshrvce@gmail.com>

* changed the sync port to dns port in flag

* [network] Limit client sync connection (#3071)

* [network] limit client connected peers
* Changed signature and added tests

* Set secure permissions on generated blskey pass file in node.sh

* Fix spellin gtypo in node.sh

* fix latest param handling in api v1

* added comment for the isGreaterThanLatestBlockNum check

* fix a nil pointer crash due to previous revert

Signed-off-by: Leo Chen <leo@harmony.one>

* fix nil pointer crash

Signed-off-by: Leo Chen <leo@harmony.one>

* fix nil pointer of block

Signed-off-by: Leo Chen <leo@harmony.one>

* [rpc] add viewID and epoch to RPCMarshalBlock (#3009)

* [rpc] add viewID and epoch to RPCMarshalBlock

* add apt-get update

* Do not rollback current block on failed block sync (#3101)

Co-authored-by: Ganesha Upadhyaya <ganeshrvce@gmail.com>
Co-authored-by: Rongjian Lan <rongjian.lan@gmail.com>
Co-authored-by: Jacky Wang <jackyw.se@gmail.com>
Co-authored-by: Janet Liang <56005637+janet-harmony@users.noreply.github.com>
Co-authored-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>
Co-authored-by: Janet Liang <janet@harmony.one>
Co-authored-by: Sebastian Johnsson <sebastian.johnsson@gmail.com>
Co-authored-by: hsiung <hsiung@pinterest.com>
Co-authored-by: Dennis Won <jhwon0820@gmail.com>
Co-authored-by: Yishuang Chen <34232522+ivorytowerdds@users.noreply.github.com>
pull/3118/head
Leo Chen 5 years ago committed by GitHub
parent f322342ba6
commit 5c1cc8232c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Dockerfile
  2. 2
      Makefile
  3. 8
      api/service/explorer/service.go
  4. 39
      api/service/syncing/syncing.go
  5. 69
      api/service/syncing/syncing_test.go
  6. 9
      cmd/harmony/main.go
  7. 2
      consensus/consensus_service.go
  8. 15
      consensus/leader.go
  9. 4
      consensus/votepower/roster.go
  10. 2
      core/block_validator.go
  11. 6
      core/blockchain.go
  12. 7
      core/staking_verifier.go
  13. 2043
      core/staking_verifier_test.go
  14. 14
      core/tx_pool_test.go
  15. 29
      hmy/api_backend.go
  16. 5
      internal/chain/engine.go
  17. 8
      internal/configs/sharding/testnet.go
  18. 4
      internal/configs/viper/viper_config.go
  19. 2
      internal/hmyapi/apiv1/backend.go
  20. 18
      internal/hmyapi/apiv1/blockchain.go
  21. 4
      internal/hmyapi/apiv1/transactionpool.go
  22. 4
      internal/hmyapi/apiv1/types.go
  23. 8
      internal/hmyapi/apiv1/util.go
  24. 2
      internal/hmyapi/apiv2/backend.go
  25. 22
      internal/hmyapi/apiv2/blockchain.go
  26. 4
      internal/hmyapi/apiv2/sendtxargs.go
  27. 8
      internal/hmyapi/apiv2/transactionpool.go
  28. 6
      internal/hmyapi/apiv2/types.go
  29. 8
      internal/hmyapi/apiv2/util.go
  30. 2
      internal/hmyapi/backend.go
  31. 6
      internal/params/config.go
  32. 17
      node/node.go
  33. 59
      node/node_syncing.go
  34. 4
      scripts/go_executable_build.sh
  35. 40
      scripts/node.sh
  36. 10
      staking/availability/measure_test.go
  37. 13
      staking/effective/eligible.go
  38. 3
      staking/slash/double-sign_test.go
  39. 4
      staking/slash/interface_test.go
  40. 4
      staking/types/test/copy.go
  41. 19
      staking/types/test/copy_test.go
  42. 209
      staking/types/test/equal.go
  43. 37
      staking/types/test/equal_test.go
  44. 118
      staking/types/test/prototype.go
  45. 79
      staking/types/test/prototype_test.go
  46. 5
      staking/types/validator.go
  47. 3
      staking/types/validator_test.go
  48. 3
      webhooks/yaml.go

@ -16,6 +16,7 @@ ENV LD_LIBRARY_PATH=${BLS_DIR}/lib:${MCL_DIR}/lib
ENV GIMME_GO_VERSION="1.14.1" ENV GIMME_GO_VERSION="1.14.1"
ENV PATH="/root/bin:${PATH}" ENV PATH="/root/bin:${PATH}"
RUN apt-get update -y
RUN apt install libgmp-dev libssl-dev curl git \ RUN apt install libgmp-dev libssl-dev curl git \
psmisc dnsutils jq make gcc g++ bash tig tree sudo vim \ psmisc dnsutils jq make gcc g++ bash tig tree sudo vim \
silversearcher-ag unzip emacs-nox nano bash-completion -y silversearcher-ag unzip emacs-nox nano bash-completion -y

@ -16,7 +16,7 @@ libs:
make -C $(TOP)/bls BLS_SWAP_G=1 -j8 make -C $(TOP)/bls BLS_SWAP_G=1 -j8
exe: exe:
./scripts/go_executable_build.sh ./scripts/go_executable_build.sh -S
race: race:
./scripts/go_executable_build.sh -r ./scripts/go_executable_build.sh -r

@ -102,7 +102,13 @@ func (s *Service) Run() *http.Server {
// Do serving now. // Do serving now.
utils.Logger().Info().Str("port", GetExplorerPort(s.Port)).Msg("Listening") utils.Logger().Info().Str("port", GetExplorerPort(s.Port)).Msg("Listening")
server := &http.Server{Addr: addr, Handler: s.router} server := &http.Server{
Addr: addr,
Handler: s.router,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
go func() { go func() {
if err := server.ListenAndServe(); err != nil { if err := server.ListenAndServe(); err != nil {
utils.Logger().Warn().Err(err).Msg("server.ListenAndServe()") utils.Logger().Warn().Err(err).Msg("server.ListenAndServe()")

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"math/rand"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
@ -36,6 +37,11 @@ const (
verifyHeaderBatchSize uint64 = 100 // block chain header verification batch size verifyHeaderBatchSize uint64 = 100 // block chain header verification batch size
SyncLoopFrequency = 1 // unit in second SyncLoopFrequency = 1 // unit in second
LastMileBlocksSize = 50 LastMileBlocksSize = 50
// after cutting off a number of connected peers, the result number of peers
// shall be between numPeersLowBound and numPeersHighBound
numPeersLowBound = 3
numPeersHighBound = 5
) )
// SyncPeerConfig is peer config to sync. // SyncPeerConfig is peer config to sync.
@ -225,6 +231,10 @@ func (peerConfig *SyncPeerConfig) GetBlocks(hashes [][]byte) ([][]byte, error) {
// CreateSyncConfig creates SyncConfig for StateSync object. // CreateSyncConfig creates SyncConfig for StateSync object.
func (ss *StateSync) CreateSyncConfig(peers []p2p.Peer, isBeacon bool) error { func (ss *StateSync) CreateSyncConfig(peers []p2p.Peer, isBeacon bool) error {
// limit the number of dns peers to connect
randSeed := time.Now().UnixNano()
peers = limitNumPeers(peers, randSeed)
utils.Logger().Debug(). utils.Logger().Debug().
Int("len", len(peers)). Int("len", len(peers)).
Bool("isBeacon", isBeacon). Bool("isBeacon", isBeacon).
@ -237,6 +247,7 @@ func (ss *StateSync) CreateSyncConfig(peers []p2p.Peer, isBeacon bool) error {
ss.syncConfig.CloseConnections() ss.syncConfig.CloseConnections()
} }
ss.syncConfig = &SyncConfig{} ss.syncConfig = &SyncConfig{}
var wg sync.WaitGroup var wg sync.WaitGroup
for _, peer := range peers { for _, peer := range peers {
wg.Add(1) wg.Add(1)
@ -263,6 +274,34 @@ func (ss *StateSync) CreateSyncConfig(peers []p2p.Peer, isBeacon bool) error {
return nil return nil
} }
// limitNumPeers limits number of peers to release some server end sources.
func limitNumPeers(ps []p2p.Peer, randSeed int64) []p2p.Peer {
targetSize := calcNumPeersWithBound(len(ps), numPeersLowBound, numPeersHighBound)
if len(ps) <= targetSize {
return ps
}
r := rand.New(rand.NewSource(randSeed))
r.Shuffle(len(ps), func(i, j int) { ps[i], ps[j] = ps[j], ps[i] })
return ps[:targetSize]
}
// Peers are expected to limited at half of the size, capped between lowBound and highBound.
func calcNumPeersWithBound(size int, lowBound, highBound int) int {
if size < lowBound {
return size
}
expLen := size / 2
if expLen < lowBound {
expLen = lowBound
}
if expLen > highBound {
expLen = highBound
}
return expLen
}
// GetActivePeerNumber returns the number of active peers // GetActivePeerNumber returns the number of active peers
func (ss *StateSync) GetActivePeerNumber() int { func (ss *StateSync) GetActivePeerNumber() int {
if ss.syncConfig == nil { if ss.syncConfig == nil {

@ -1,9 +1,12 @@
package syncing package syncing
import ( import (
"fmt"
"reflect"
"testing" "testing"
"github.com/harmony-one/harmony/api/service/syncing/downloader" "github.com/harmony-one/harmony/api/service/syncing/downloader"
"github.com/harmony-one/harmony/p2p"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -49,3 +52,69 @@ func TestCreateStateSync(t *testing.T) {
t.Error("Unable to create stateSync") t.Error("Unable to create stateSync")
} }
} }
func TestLimitPeersWithBound(t *testing.T) {
tests := []struct {
size int
expSize int
}{
{0, 0},
{1, 1},
{3, 3},
{4, 3},
{7, 3},
{8, 4},
{10, 5},
{11, 5},
{100, 5},
}
for _, test := range tests {
ps := makePeersForTest(test.size)
res := limitNumPeers(ps, 1)
if len(res) != test.expSize {
t.Errorf("result size unexpected: %v / %v", len(res), test.expSize)
}
if err := checkTestPeerDuplicity(res); err != nil {
t.Error(err)
}
}
}
func TestLimitPeersWithBound_random(t *testing.T) {
ps1 := makePeersForTest(100)
ps2 := makePeersForTest(100)
s1, s2 := int64(1), int64(2)
res1 := limitNumPeers(ps1, s1)
res2 := limitNumPeers(ps2, s2)
if reflect.DeepEqual(res1, res2) {
t.Fatal("not randomized limit peer")
}
}
func makePeersForTest(size int) []p2p.Peer {
ps := make([]p2p.Peer, 0, size)
for i := 0; i != size; i++ {
ps = append(ps, p2p.Peer{
IP: makeTestPeerIP(i),
})
}
return ps
}
func checkTestPeerDuplicity(ps []p2p.Peer) error {
m := make(map[string]struct{})
for _, p := range ps {
if _, ok := m[p.IP]; ok {
return fmt.Errorf("duplicate ip")
}
m[p.IP] = struct{}{}
}
return nil
}
func makeTestPeerIP(i interface{}) string {
return fmt.Sprintf("%v", i)
}

@ -72,6 +72,7 @@ var (
onlyLogTps = flag.Bool("only_log_tps", false, "Only log TPS if true") onlyLogTps = flag.Bool("only_log_tps", false, "Only log TPS if true")
dnsZone = flag.String("dns_zone", "", "if given and not empty, use peers from the zone (default: use libp2p peer discovery instead)") dnsZone = flag.String("dns_zone", "", "if given and not empty, use peers from the zone (default: use libp2p peer discovery instead)")
dnsFlag = flag.Bool("dns", true, "[deprecated] equivalent to -dns_zone t.hmny.io") dnsFlag = flag.Bool("dns", true, "[deprecated] equivalent to -dns_zone t.hmny.io")
dnsPort = flag.String("dns_port", "9000", "port of dns node")
//Leader needs to have a minimal number of peers to start consensus //Leader needs to have a minimal number of peers to start consensus
minPeers = flag.Int("min_peers", 32, "Minimal number of Peers in shard") minPeers = flag.Int("min_peers", 32, "Minimal number of Peers in shard")
// Key file to store the private key // Key file to store the private key
@ -111,6 +112,7 @@ var (
revertBeacon = flag.Bool("revert_beacon", false, "Whether to revert beacon chain or the chain this node is assigned to") revertBeacon = flag.Bool("revert_beacon", false, "Whether to revert beacon chain or the chain this node is assigned to")
// Blacklist of addresses // Blacklist of addresses
blacklistPath = flag.String("blacklist", "./.hmy/blacklist.txt", "Path to newline delimited file of blacklisted wallet addresses") blacklistPath = flag.String("blacklist", "./.hmy/blacklist.txt", "Path to newline delimited file of blacklisted wallet addresses")
broadcastInvalidTx = flag.Bool("broadcast_invalid_tx", false, "Broadcast invalid transactions to sync pool state (default: false)")
webHookYamlPath = flag.String( webHookYamlPath = flag.String(
"webhook_yaml", "", "path for yaml config reporting double signing", "webhook_yaml", "", "path for yaml config reporting double signing",
) )
@ -290,7 +292,7 @@ func readMultiBLSKeys(consensusMultiBLSPriKey *multibls.PrivateKey, consensusMul
os.Exit(100) os.Exit(100)
} }
keyFiles := []os.FileInfo{} var keyFiles []os.FileInfo
legacyBLSFile := true legacyBLSFile := true
if len(awsEncryptedBLSKeyFiles) > 0 { if len(awsEncryptedBLSKeyFiles) > 0 {
@ -460,6 +462,7 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir} chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir}
currentNode := node.New(myHost, currentConsensus, chainDBFactory, blacklist, *isArchival) currentNode := node.New(myHost, currentConsensus, chainDBFactory, blacklist, *isArchival)
currentNode.BroadcastInvalidTx = *broadcastInvalidTx
switch { switch {
case *networkType == nodeconfig.Localnet: case *networkType == nodeconfig.Localnet:
@ -474,9 +477,9 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
currentNode.SyncingPeerProvider = node.NewLocalSyncingPeerProvider( currentNode.SyncingPeerProvider = node.NewLocalSyncingPeerProvider(
6000, uint16(selfPort), epochConfig.NumShards(), uint32(epochConfig.NumNodesPerShard())) 6000, uint16(selfPort), epochConfig.NumShards(), uint32(epochConfig.NumNodesPerShard()))
case *dnsZone != "": case *dnsZone != "":
currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider(*dnsZone, syncing.GetSyncingPort(*port)) currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider(*dnsZone, syncing.GetSyncingPort(*dnsPort))
case *dnsFlag: case *dnsFlag:
currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider("t.hmny.io", syncing.GetSyncingPort(*port)) currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider("t.hmny.io", syncing.GetSyncingPort(*dnsPort))
default: default:
currentNode.SyncingPeerProvider = node.NewLegacySyncingPeerProvider(currentNode) currentNode.SyncingPeerProvider = node.NewLegacySyncingPeerProvider(currentNode)

@ -418,7 +418,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode {
consensus.Decider = decider consensus.Decider = decider
} }
committeeToSet := &shard.Committee{} var committeeToSet *shard.Committee
epochToSet := curEpoch epochToSet := curEpoch
hasError := false hasError := false
curShardState, err := committee.WithStakingEnabled.ReadFromDB( curShardState, err := committee.WithStakingEnabled.ReadFromDB(

@ -262,20 +262,19 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) {
return return
} }
viewID := consensus.viewID
quorumIsMet := consensus.Decider.IsQuorumAchieved(quorum.Commit) quorumIsMet := consensus.Decider.IsQuorumAchieved(quorum.Commit)
if !quorumWasMet && quorumIsMet { if !quorumWasMet && quorumIsMet {
logger.Info().Msg("[OnCommit] 2/3 Enough commits received") logger.Info().Msg("[OnCommit] 2/3 Enough commits received")
go func(viewID uint64) {
next := consensus.NextBlockDue
consensus.getLogger().Info().Msg("[OnCommit] Starting Grace Period") consensus.getLogger().Info().Msg("[OnCommit] Starting Grace Period")
// Always wait for 2 seconds as minimum grace period time.AfterFunc(2*time.Second, func() {
time.Sleep(2 * time.Second) <-time.After(time.Until(next))
if n := time.Now(); n.Before(consensus.NextBlockDue) {
// Sleep to wait for the full block time
time.Sleep(consensus.NextBlockDue.Sub(n))
}
logger.Info().Msg("[OnCommit] Commit Grace Period Ended") logger.Info().Msg("[OnCommit] Commit Grace Period Ended")
consensus.commitFinishChan <- viewID consensus.commitFinishChan <- viewID
}(consensus.viewID) })
consensus.msgSender.StopRetry(msg_pb.MessageType_PREPARED) consensus.msgSender.StopRetry(msg_pb.MessageType_PREPARED)
} }

@ -143,13 +143,9 @@ func AggregateRosters(
AccommodateHarmonyVote: *voteCard, AccommodateHarmonyVote: *voteCard,
ShardID: roster.ShardID, ShardID: roster.ShardID,
} }
if _, ok := result[voteCard.EarningAccount]; ok {
result[voteCard.EarningAccount] = append( result[voteCard.EarningAccount] = append(
result[voteCard.EarningAccount], voterID, result[voteCard.EarningAccount], voterID,
) )
} else {
result[voteCard.EarningAccount] = []VoteOnSubcomittee{voterID}
}
} }
} }
} }

@ -36,7 +36,7 @@ import (
// BlockValidator is responsible for validating block headers, uncles and // BlockValidator is responsible for validating block headers, uncles and
// processed state. // processed state.
// //
// BlockValidator implements Validator. // BlockValidator implements validator.
type BlockValidator struct { type BlockValidator struct {
config *params.ChainConfig // Chain configuration options config *params.ChainConfig // Chain configuration options
bc *BlockChain // Canonical block chain bc *BlockChain // Canonical block chain

@ -102,9 +102,9 @@ type CacheConfig struct {
// block. The Blockchain manages chain imports, reverts, chain reorganisations. // block. The Blockchain manages chain imports, reverts, chain reorganisations.
// //
// Importing blocks in to the block chain happens according to the set of rules // Importing blocks in to the block chain happens according to the set of rules
// defined by the two stage Validator. Processing of blocks is done using the // defined by the two stage validator. Processing of blocks is done using the
// Processor which processes the included transaction. The validation of the state // Processor which processes the included transaction. The validation of the state
// is done in the second part of the Validator. Failing results in aborting of // is done in the second part of the validator. Failing results in aborting of
// the import. // the import.
// //
// The BlockChain also helps in returning blocks from **any** chain included // The BlockChain also helps in returning blocks from **any** chain included
@ -170,7 +170,7 @@ type BlockChain struct {
} }
// NewBlockChain returns a fully initialised block chain using information // NewBlockChain returns a fully initialised block chain using information
// available in the database. It initialises the default Ethereum Validator and // available in the database. It initialises the default Ethereum validator and
// Processor. // Processor.
func NewBlockChain( func NewBlockChain(
db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig,

@ -111,9 +111,8 @@ func VerifyAndCreateValidatorFromMsg(
wrapper.Delegations = []staking.Delegation{ wrapper.Delegations = []staking.Delegation{
staking.NewDelegation(v.Address, msg.Amount), staking.NewDelegation(v.Address, msg.Amount),
} }
zero := big.NewInt(0) wrapper.Counters.NumBlocksSigned = big.NewInt(0)
wrapper.Counters.NumBlocksSigned = zero wrapper.Counters.NumBlocksToSign = big.NewInt(0)
wrapper.Counters.NumBlocksToSign = zero
wrapper.BlockReward = big.NewInt(0) wrapper.BlockReward = big.NewInt(0)
maxBLSKeyAllowed := shard.ExternalSlotsAvailableForEpoch(epoch) / 3 maxBLSKeyAllowed := shard.ExternalSlotsAvailableForEpoch(epoch) / 3
if err := wrapper.SanityCheck(maxBLSKeyAllowed); err != nil { if err := wrapper.SanityCheck(maxBLSKeyAllowed); err != nil {
@ -167,7 +166,7 @@ func VerifyAndEditValidatorFromMsg(
snapshotValidator, err := chainContext.ReadValidatorSnapshot(wrapper.Address) snapshotValidator, err := chainContext.ReadValidatorSnapshot(wrapper.Address)
if err != nil { if err != nil {
return nil, errors.WithMessage(err, "Validator snapshot not found.") return nil, errors.WithMessage(err, "validator snapshot not found.")
} }
rateAtBeginningOfEpoch := snapshotValidator.Validator.Rate rateAtBeginningOfEpoch := snapshotValidator.Validator.Rate

File diff suppressed because it is too large Load Diff

@ -116,12 +116,12 @@ func stakingCreateValidatorTransaction(key *ecdsa.PrivateKey) (*staking.StakingT
MaxRate: maxRate, MaxRate: maxRate,
MaxChangeRate: maxChangeRate, MaxChangeRate: maxChangeRate,
}, },
MinSelfDelegation: tenK, MinSelfDelegation: tenKOnes,
MaxTotalDelegation: twelveK, MaxTotalDelegation: twelveKOnes,
ValidatorAddress: crypto.PubkeyToAddress(key.PublicKey), ValidatorAddress: crypto.PubkeyToAddress(key.PublicKey),
SlotPubKeys: []shard.BLSPublicKey{pub}, SlotPubKeys: []shard.BLSPublicKey{pub},
SlotKeySigs: []shard.BLSSignature{sig}, SlotKeySigs: []shard.BLSSignature{sig},
Amount: tenK, Amount: tenKOnes,
} }
} }
@ -374,8 +374,8 @@ func TestErrorSink(t *testing.T) {
t.Error("expected errored transaction in tx pool") t.Error("expected errored transaction in tx pool")
} }
pool.currentState.SetBalance(from, twelveK) pool.currentState.SetBalance(from, twelveKOnes)
pool.currentState.SetBalance(fromStx, twelveK) pool.currentState.SetBalance(fromStx, twelveKOnes)
if err := pool.AddRemote(tx); err != nil { if err := pool.AddRemote(tx); err != nil {
t.Error("expected successful transaction got", err) t.Error("expected successful transaction got", err)
} }
@ -403,7 +403,7 @@ func TestCreateValidatorTransaction(t *testing.T) {
t.Errorf("cannot create new staking transaction, %v\n", err) t.Errorf("cannot create new staking transaction, %v\n", err)
} }
senderAddr, _ := stx.SenderAddress() senderAddr, _ := stx.SenderAddress()
pool.currentState.AddBalance(senderAddr, tenK) pool.currentState.AddBalance(senderAddr, tenKOnes)
// Add additional create validator tx cost // Add additional create validator tx cost
pool.currentState.AddBalance(senderAddr, cost) pool.currentState.AddBalance(senderAddr, cost)
@ -429,7 +429,7 @@ func TestMixedTransactions(t *testing.T) {
t.Errorf("cannot create new staking transaction, %v\n", err) t.Errorf("cannot create new staking transaction, %v\n", err)
} }
stxAddr, _ := stx.SenderAddress() stxAddr, _ := stx.SenderAddress()
pool.currentState.AddBalance(stxAddr, tenK) pool.currentState.AddBalance(stxAddr, tenKOnes)
// Add additional create validator tx cost // Add additional create validator tx cost
pool.currentState.AddBalance(stxAddr, cost) pool.currentState.AddBalance(stxAddr, cost)

@ -16,6 +16,7 @@ import (
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
@ -34,6 +35,11 @@ import (
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
) )
var (
// ErrFinalizedTransaction is returned if the transaction to be submitted is already on-chain
ErrFinalizedTransaction = errors.New("transaction already finalized")
)
// APIBackend An implementation of internal/hmyapi/Backend. Full client. // APIBackend An implementation of internal/hmyapi/Backend. Full client.
type APIBackend struct { type APIBackend struct {
hmy *Harmony hmy *Harmony
@ -122,8 +128,11 @@ func (b *APIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uin
// SendTx ... // SendTx ...
func (b *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
b.hmy.nodeAPI.AddPendingTransaction(signedTx) tx, _, _, _ := rawdb.ReadTransaction(b.ChainDb(), signedTx.Hash())
return nil if tx == nil {
return b.hmy.nodeAPI.AddPendingTransaction(signedTx)
}
return ErrFinalizedTransaction
} }
// ChainConfig ... // ChainConfig ...
@ -362,11 +371,12 @@ func (b *APIBackend) IsLeader() bool {
} }
// SendStakingTx adds a staking transaction // SendStakingTx adds a staking transaction
func (b *APIBackend) SendStakingTx( func (b *APIBackend) SendStakingTx(ctx context.Context, signedStakingTx *staking.StakingTransaction) error {
ctx context.Context, stx, _, _, _ := rawdb.ReadStakingTransaction(b.ChainDb(), signedStakingTx.Hash())
newStakingTx *staking.StakingTransaction) error { if stx == nil {
b.hmy.nodeAPI.AddPendingStakingTransaction(newStakingTx) return b.hmy.nodeAPI.AddPendingStakingTransaction(signedStakingTx)
return nil }
return ErrFinalizedTransaction
} }
// GetElectedValidatorAddresses returns the address of elected validators for current epoch // GetElectedValidatorAddresses returns the address of elected validators for current epoch
@ -387,7 +397,7 @@ var (
// GetValidatorInformation returns the information of validator // GetValidatorInformation returns the information of validator
func (b *APIBackend) GetValidatorInformation( func (b *APIBackend) GetValidatorInformation(
addr common.Address, block *types.Block, addr common.Address, block *types.Block,
) (*staking.ValidatorRPCEnchanced, error) { ) (*staking.ValidatorRPCEnhanced, error) {
bc := b.hmy.BlockChain() bc := b.hmy.BlockChain()
wrapper, err := bc.ReadValidatorInformationAt(addr, block.Root()) wrapper, err := bc.ReadValidatorInformationAt(addr, block.Root())
if err != nil { if err != nil {
@ -399,7 +409,7 @@ func (b *APIBackend) GetValidatorInformation(
// At the last block of epoch, block epoch is e while val.LastEpochInCommittee // At the last block of epoch, block epoch is e while val.LastEpochInCommittee
// is already updated to e+1. So need the >= check rather than == // is already updated to e+1. So need the >= check rather than ==
inCommittee := wrapper.LastEpochInCommittee.Cmp(now) >= 0 inCommittee := wrapper.LastEpochInCommittee.Cmp(now) >= 0
defaultReply := &staking.ValidatorRPCEnchanced{ defaultReply := &staking.ValidatorRPCEnhanced{
CurrentlyInCommittee: inCommittee, CurrentlyInCommittee: inCommittee,
Wrapper: *wrapper, Wrapper: *wrapper,
Performance: nil, Performance: nil,
@ -410,6 +420,7 @@ func (b *APIBackend) GetValidatorInformation(
).String(), ).String(),
EPoSWinningStake: nil, EPoSWinningStake: nil,
BootedStatus: nil, BootedStatus: nil,
ActiveStatus: wrapper.Validator.Status.String(),
Lifetime: &staking.AccumulatedOverLifetime{ Lifetime: &staking.AccumulatedOverLifetime{
wrapper.BlockReward, wrapper.BlockReward,
wrapper.Counters, wrapper.Counters,

@ -399,12 +399,7 @@ func applySlashes(
shardID: doubleSigners[i].Evidence.Moment.ShardID, shardID: doubleSigners[i].Evidence.Moment.ShardID,
epoch: doubleSigners[i].Evidence.Moment.Epoch.Uint64(), epoch: doubleSigners[i].Evidence.Moment.Epoch.Uint64(),
} }
if _, ok := groupedRecords[thisKey]; ok {
groupedRecords[thisKey] = append(groupedRecords[thisKey], doubleSigners[i]) groupedRecords[thisKey] = append(groupedRecords[thisKey], doubleSigners[i])
} else {
groupedRecords[thisKey] = slash.Records{doubleSigners[i]}
}
} }
sortedKeys := []keyStruct{} sortedKeys := []keyStruct{}

@ -21,9 +21,9 @@ const (
testnetVdfDifficulty = 10000 // This takes about 20s to finish the vdf testnetVdfDifficulty = 10000 // This takes about 20s to finish the vdf
// TestNetHTTPPattern is the http pattern for testnet. // TestNetHTTPPattern is the http pattern for testnet.
TestNetHTTPPattern = "https://api.s%d.tn.hmny.io" TestNetHTTPPattern = "https://api.s%d.b.hmny.io"
// TestNetWSPattern is the websocket pattern for testnet. // TestNetWSPattern is the websocket pattern for testnet.
TestNetWSPattern = "wss://ws.s%d.tn.hmny.io" TestNetWSPattern = "wss://ws.s%d.b.hmny.io"
) )
func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
@ -81,5 +81,5 @@ var testnetReshardingEpoch = []*big.Int{
params.TestnetChainConfig.StakingEpoch, params.TestnetChainConfig.StakingEpoch,
} }
var testnetV0 = MustNewInstance(4, 30, 25, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch()) var testnetV0 = MustNewInstance(4, 16, 15, numeric.OneDec(), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch())
var testnetV1 = MustNewInstance(4, 50, 25, numeric.MustNewDecFromStr("0.68"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch()) var testnetV1 = MustNewInstance(4, 20, 15, numeric.MustNewDecFromStr("0.90"), genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch, TestnetSchedule.BlocksPerEpoch())

@ -87,13 +87,13 @@ func ResetConfInt(value *int, envViper *viper.Viper, configFileViper *viper.Vipe
// ResetConfBool resets Bool value to value from config files and system environment variable // ResetConfBool resets Bool value to value from config files and system environment variable
func ResetConfBool(value *bool, envViper *viper.Viper, configFileViper *viper.Viper, sectionName string, flagName string) { func ResetConfBool(value *bool, envViper *viper.Viper, configFileViper *viper.Viper, sectionName string, flagName string) {
var confRet = configFileViper.GetBool(getConfName(sectionName, flagName)) var confRet = configFileViper.GetBool(getConfName(sectionName, flagName))
if confRet != false { if confRet {
*value = confRet *value = confRet
return return
} }
var envRet = envViper.GetBool(getEnvName(sectionName, flagName)) var envRet = envViper.GetBool(getEnvName(sectionName, flagName))
if envRet != false { if envRet {
*value = envRet *value = envRet
return return
} }

@ -74,7 +74,7 @@ type Backend interface {
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnchanced, error) GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)

@ -442,7 +442,7 @@ func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address strin
return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr)) return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr))
} }
// GetBalance returns the amount of Nano for the given address in the state of the // GetBalance returns the amount of Atto for the given address in the state of the
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed. // block numbers are also allowed.
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string, blockNr rpc.BlockNumber) (*hexutil.Big, error) { func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string, blockNr rpc.BlockNumber) (*hexutil.Big, error) {
@ -632,7 +632,7 @@ func (s *PublicBlockChainAPI) GetElectedValidatorAddresses() ([]string, error) {
// GetValidatorInformation returns information about a validator. // GetValidatorInformation returns information about a validator.
func (s *PublicBlockChainAPI) GetValidatorInformation( func (s *PublicBlockChainAPI) GetValidatorInformation(
ctx context.Context, address string, ctx context.Context, address string,
) (*staking.ValidatorRPCEnchanced, error) { ) (*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -648,7 +648,7 @@ func (s *PublicBlockChainAPI) GetValidatorInformation(
// GetValidatorInformationByBlockNumber returns information about a validator. // GetValidatorInformationByBlockNumber returns information about a validator.
func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber( func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
ctx context.Context, address string, blockNr rpc.BlockNumber, ctx context.Context, address string, blockNr rpc.BlockNumber,
) (*staking.ValidatorRPCEnchanced, error) { ) (*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -666,13 +666,13 @@ func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
func (s *PublicBlockChainAPI) getAllValidatorInformation( func (s *PublicBlockChainAPI) getAllValidatorInformation(
ctx context.Context, page int, blockNr rpc.BlockNumber, ctx context.Context, page int, blockNr rpc.BlockNumber,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if page < -1 { if page < -1 {
return nil, errors.Errorf("page given %d cannot be less than -1", page) return nil, errors.Errorf("page given %d cannot be less than -1", page)
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.b.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([]*staking.ValidatorRPCEnchanced, 0), nil return make([]*staking.ValidatorRPCEnhanced, 0), nil
} }
validatorsNum := len(addresses) validatorsNum := len(addresses)
start := 0 start := 0
@ -683,7 +683,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start validatorsNum = len(addresses) - start
} }
} }
validators := make([]*staking.ValidatorRPCEnchanced, validatorsNum) validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
@ -702,7 +702,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
// If page is -1, return all instead of `validatorsPageSize` elements. // If page is -1, return all instead of `validatorsPageSize` elements.
func (s *PublicBlockChainAPI) GetAllValidatorInformation( func (s *PublicBlockChainAPI) GetAllValidatorInformation(
ctx context.Context, page int, ctx context.Context, page int,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -722,14 +722,14 @@ func (s *PublicBlockChainAPI) GetAllValidatorInformation(
if err != nil { if err != nil {
return nil, err return nil, err
} }
return res.([]*staking.ValidatorRPCEnchanced), nil return res.([]*staking.ValidatorRPCEnhanced), nil
} }
// GetAllValidatorInformationByBlockNumber returns information about all validators. // GetAllValidatorInformationByBlockNumber returns information about all validators.
// If page is -1, return all instead of `validatorsPageSize` elements. // If page is -1, return all instead of `validatorsPageSize` elements.
func (s *PublicBlockChainAPI) GetAllValidatorInformationByBlockNumber( func (s *PublicBlockChainAPI) GetAllValidatorInformationByBlockNumber(
ctx context.Context, page int, blockNr rpc.BlockNumber, ctx context.Context, page int, blockNr rpc.BlockNumber,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }

@ -39,8 +39,8 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa
// GetTransactionsHistory returns the list of transactions hashes that involve a particular address. // GetTransactionsHistory returns the list of transactions hashes that involve a particular address.
func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) {
address := args.Address var address string
result := []common.Hash{} var result []common.Hash
var err error var err error
if strings.HasPrefix(args.Address, "one1") { if strings.HasPrefix(args.Address, "one1") {
address = args.Address address = args.Address

@ -353,6 +353,8 @@ func newRPCStakingTransaction(tx *types2.StakingTransaction, blockHash common.Ha
// RPCBlock represents a block that will serialize to the RPC representation of a block // RPCBlock represents a block that will serialize to the RPC representation of a block
type RPCBlock struct { type RPCBlock struct {
Number *hexutil.Big `json:"number"` Number *hexutil.Big `json:"number"`
ViewID *hexutil.Big `json:"viewID"`
Epoch *hexutil.Big `json:"epoch"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
ParentHash common.Hash `json:"parentHash"` ParentHash common.Hash `json:"parentHash"`
Nonce types.BlockNonce `json:"nonce"` Nonce types.BlockNonce `json:"nonce"`
@ -382,6 +384,8 @@ func RPCMarshalBlock(b *types.Block, blockArgs BlockArgs) (map[string]interface{
head := b.Header() // copies the header once head := b.Header() // copies the header once
fields := map[string]interface{}{ fields := map[string]interface{}{
"number": (*hexutil.Big)(head.Number()), "number": (*hexutil.Big)(head.Number()),
"viewID": (*hexutil.Big)(head.ViewID()),
"epoch": (*hexutil.Big)(head.Epoch()),
"hash": b.Hash(), "hash": b.Hash(),
"parentHash": head.ParentHash(), "parentHash": head.ParentHash(),
"nonce": 0, // Remove this because we don't have it in our header "nonce": 0, // Remove this because we don't have it in our header

@ -36,7 +36,9 @@ func SubmitTransaction(
ctx context.Context, b Backend, tx *types.Transaction, ctx context.Context, b Backend, tx *types.Transaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil { if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err // legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit transaction")
return tx.Hash(), nil
} }
if tx.To() == nil { if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch()) signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch())
@ -63,7 +65,9 @@ func SubmitStakingTransaction(
ctx context.Context, b Backend, tx *staking.StakingTransaction, ctx context.Context, b Backend, tx *staking.StakingTransaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendStakingTx(ctx, tx); err != nil { if err := b.SendStakingTx(ctx, tx); err != nil {
return common.Hash{}, err // legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction")
return tx.Hash(), nil
} }
utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction") utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction")
return tx.Hash(), nil return tx.Hash(), nil

@ -70,7 +70,7 @@ type Backend interface {
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnchanced, error) GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)

@ -395,12 +395,12 @@ func (s *PublicBlockChainAPI) GetAccountNonce(ctx context.Context, address strin
return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr)) return s.b.GetAccountNonce(ctx, addr, rpc.BlockNumber(blockNr))
} }
// GetBalance returns the amount of Nano for the given address in the state of the // GetBalance returns the amount of Atto for the given address in the state of the
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed. // block numbers are also allowed.
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string, blockNr rpc.BlockNumber) (*big.Int, error) { func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string) (*big.Int, error) {
addr := internal_common.ParseAddr(address) addr := internal_common.ParseAddr(address)
return s.b.GetBalance(ctx, addr, rpc.BlockNumber(blockNr)) return s.b.GetBalance(ctx, addr, rpc.BlockNumber(-1))
} }
// BlockNumber returns the block number of the chain head. // BlockNumber returns the block number of the chain head.
@ -578,7 +578,7 @@ func (s *PublicBlockChainAPI) GetElectedValidatorAddresses() ([]string, error) {
// GetValidatorInformation .. // GetValidatorInformation ..
func (s *PublicBlockChainAPI) GetValidatorInformation( func (s *PublicBlockChainAPI) GetValidatorInformation(
ctx context.Context, address string, ctx context.Context, address string,
) (*staking.ValidatorRPCEnchanced, error) { ) (*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -594,7 +594,7 @@ func (s *PublicBlockChainAPI) GetValidatorInformation(
// GetValidatorInformationByBlockNumber .. // GetValidatorInformationByBlockNumber ..
func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber( func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
ctx context.Context, address string, blockNr uint64, ctx context.Context, address string, blockNr uint64,
) (*staking.ValidatorRPCEnchanced, error) { ) (*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -612,13 +612,13 @@ func (s *PublicBlockChainAPI) GetValidatorInformationByBlockNumber(
func (s *PublicBlockChainAPI) getAllValidatorInformation( func (s *PublicBlockChainAPI) getAllValidatorInformation(
ctx context.Context, page int, blockNr rpc.BlockNumber, ctx context.Context, page int, blockNr rpc.BlockNumber,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if page < -1 { if page < -1 {
return nil, errors.Errorf("page given %d cannot be less than -1", page) return nil, errors.Errorf("page given %d cannot be less than -1", page)
} }
addresses := s.b.GetAllValidatorAddresses() addresses := s.b.GetAllValidatorAddresses()
if page != -1 && len(addresses) <= page*validatorsPageSize { if page != -1 && len(addresses) <= page*validatorsPageSize {
return make([]*staking.ValidatorRPCEnchanced, 0), nil return make([]*staking.ValidatorRPCEnhanced, 0), nil
} }
validatorsNum := len(addresses) validatorsNum := len(addresses)
start := 0 start := 0
@ -629,7 +629,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
validatorsNum = len(addresses) - start validatorsNum = len(addresses) - start
} }
} }
validators := make([]*staking.ValidatorRPCEnchanced, validatorsNum) validators := make([]*staking.ValidatorRPCEnhanced, validatorsNum)
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr)) block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(blockNr))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr) return nil, errors.Wrapf(err, "could not retrieve the block information for block number: %d", blockNr)
@ -648,7 +648,7 @@ func (s *PublicBlockChainAPI) getAllValidatorInformation(
// If page is -1, return all else return the pagination. // If page is -1, return all else return the pagination.
func (s *PublicBlockChainAPI) GetAllValidatorInformation( func (s *PublicBlockChainAPI) GetAllValidatorInformation(
ctx context.Context, page int, ctx context.Context, page int,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }
@ -669,7 +669,7 @@ func (s *PublicBlockChainAPI) GetAllValidatorInformation(
if err != nil { if err != nil {
return nil, err return nil, err
} }
return res.([]*staking.ValidatorRPCEnchanced), nil return res.([]*staking.ValidatorRPCEnhanced), nil
} }
@ -677,7 +677,7 @@ func (s *PublicBlockChainAPI) GetAllValidatorInformation(
// If page is -1, return all else return the pagination. // If page is -1, return all else return the pagination.
func (s *PublicBlockChainAPI) GetAllValidatorInformationByBlockNumber( func (s *PublicBlockChainAPI) GetAllValidatorInformationByBlockNumber(
ctx context.Context, page int, blockNr uint64, ctx context.Context, page int, blockNr uint64,
) ([]*staking.ValidatorRPCEnchanced, error) { ) ([]*staking.ValidatorRPCEnhanced, error) {
if err := s.isBeaconShard(); err != nil { if err := s.isBeaconShard(); err != nil {
return nil, err return nil, err
} }

@ -33,14 +33,14 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
*(*uint64)(args.Gas) = 90000 *(*uint64)(args.Gas) = 90000
} }
// TODO(ricl): add check for shardID // TODO(ricl): add check for shardID
if args.GasPrice == nil { // if args.GasPrice == nil {
// TODO(ricl): port // TODO(ricl): port
// price, err := b.SuggestPrice(ctx) // price, err := b.SuggestPrice(ctx)
// if err != nil { // if err != nil {
// return err // return err
// } // }
// args.GasPrice = (*hexutil.Big)(price) // args.GasPrice = (*hexutil.Big)(price)
} // }
if args.Value == nil { if args.Value == nil {
args.Value = new(hexutil.Big) args.Value = new(hexutil.Big)
} }

@ -39,8 +39,8 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa
// GetTransactionsHistory returns the list of transactions hashes that involve a particular address. // GetTransactionsHistory returns the list of transactions hashes that involve a particular address.
func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) {
address := args.Address var address string
result := []common.Hash{} var result []common.Hash
var err error var err error
if strings.HasPrefix(args.Address, "one1") { if strings.HasPrefix(args.Address, "one1") {
address = args.Address address = args.Address
@ -118,8 +118,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, has
// GetStakingTransactionsHistory returns the list of transactions hashes that involve a particular address. // GetStakingTransactionsHistory returns the list of transactions hashes that involve a particular address.
func (s *PublicTransactionPoolAPI) GetStakingTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetStakingTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) {
address := args.Address var address string
result := []common.Hash{} var result []common.Hash
var err error var err error
if strings.HasPrefix(args.Address, "one1") { if strings.HasPrefix(args.Address, "one1") {
address = args.Address address = args.Address

@ -221,7 +221,7 @@ func newRPCStakingTransaction(
stakingTxType := tx.StakingType() stakingTxType := tx.StakingType()
message := tx.StakingMessage() message := tx.StakingMessage()
fields := make(map[string]interface{}, 0) fields := make(map[string]interface{})
switch stakingTxType { switch stakingTxType {
case types2.DirectiveCreateValidator: case types2.DirectiveCreateValidator:
@ -355,6 +355,8 @@ func newRPCStakingTransaction(
// RPCBlock represents a block that will serialize to the RPC representation of a block // RPCBlock represents a block that will serialize to the RPC representation of a block
type RPCBlock struct { type RPCBlock struct {
Number *big.Int `json:"number"` Number *big.Int `json:"number"`
ViewID *big.Int `json:"viewID"`
Epoch *big.Int `json:"epoch"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
ParentHash common.Hash `json:"parentHash"` ParentHash common.Hash `json:"parentHash"`
Nonce types.BlockNonce `json:"nonce"` Nonce types.BlockNonce `json:"nonce"`
@ -384,6 +386,8 @@ func RPCMarshalBlock(b *types.Block, blockArgs BlockArgs) (map[string]interface{
head := b.Header() // copies the header once head := b.Header() // copies the header once
fields := map[string]interface{}{ fields := map[string]interface{}{
"number": (*big.Int)(head.Number()), "number": (*big.Int)(head.Number()),
"viewID": (*big.Int)(head.ViewID()),
"epoch": (*big.Int)(head.Epoch()),
"hash": b.Hash(), "hash": b.Hash(),
"parentHash": head.ParentHash(), "parentHash": head.ParentHash(),
"nonce": 0, // Remove this because we don't have it in our header "nonce": 0, // Remove this because we don't have it in our header

@ -36,7 +36,9 @@ func SubmitTransaction(
ctx context.Context, b Backend, tx *types.Transaction, ctx context.Context, b Backend, tx *types.Transaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil { if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err // legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit transaction")
return tx.Hash(), nil
} }
if tx.To() == nil { if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch()) signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Epoch())
@ -63,7 +65,9 @@ func SubmitStakingTransaction(
ctx context.Context, b Backend, tx *staking.StakingTransaction, ctx context.Context, b Backend, tx *staking.StakingTransaction,
) (common.Hash, error) { ) (common.Hash, error) {
if err := b.SendStakingTx(ctx, tx); err != nil { if err := b.SendStakingTx(ctx, tx); err != nil {
return common.Hash{}, err // legacy behavior is to never return error and always return tx hash
utils.Logger().Warn().Err(err).Msg("Could not submit staking transaction")
return tx.Hash(), nil
} }
utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction") utils.Logger().Info().Str("fullhash", tx.Hash().Hex()).Msg("Submitted Staking transaction")
return tx.Hash(), nil return tx.Hash(), nil

@ -64,7 +64,7 @@ type Backend interface {
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetElectedValidatorAddresses() []common.Address GetElectedValidatorAddresses() []common.Address
GetAllValidatorAddresses() []common.Address GetAllValidatorAddresses() []common.Address
GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnchanced, error) GetValidatorInformation(addr common.Address, block *types.Block) (*staking.ValidatorRPCEnhanced, error)
GetDelegationsByValidator(validator common.Address) []*staking.Delegation GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation) GetDelegationsByDelegatorByBlock(delegator common.Address, block *types.Block) ([]common.Address, []*staking.Delegation)

@ -40,9 +40,9 @@ var (
TestnetChainConfig = &ChainConfig{ TestnetChainConfig = &ChainConfig{
ChainID: TestnetChainID, ChainID: TestnetChainID,
CrossTxEpoch: big.NewInt(0), CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(4), CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(4), StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(2), PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0), QuickUnlockEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0), EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0), S3Epoch: big.NewInt(0),

@ -156,6 +156,8 @@ type Node struct {
keysToAddrsMutex sync.Mutex keysToAddrsMutex sync.Mutex
// TransactionErrorSink contains error messages for any failed transaction, in memory only // TransactionErrorSink contains error messages for any failed transaction, in memory only
TransactionErrorSink *types.TransactionErrorSink TransactionErrorSink *types.TransactionErrorSink
// BroadcastInvalidTx flag is considered when adding pending tx to tx-pool
BroadcastInvalidTx bool
} }
// Blockchain returns the blockchain for the node's current shard. // Blockchain returns the blockchain for the node's current shard.
@ -259,14 +261,20 @@ func (node *Node) AddPendingStakingTransaction(
) error { ) error {
if node.NodeConfig.ShardID == shard.BeaconChainShardID { if node.NodeConfig.ShardID == shard.BeaconChainShardID {
errs := node.addPendingStakingTransactions(staking.StakingTransactions{newStakingTx}) errs := node.addPendingStakingTransactions(staking.StakingTransactions{newStakingTx})
var err error
for i := range errs { for i := range errs {
if errs[i] != nil { if errs[i] != nil {
return errs[i] utils.Logger().Info().Err(errs[i]).Msg("[AddPendingStakingTransaction] Failed adding new staking transaction")
err = errs[i]
break
} }
} }
if err == nil || node.BroadcastInvalidTx {
utils.Logger().Info().Str("Hash", newStakingTx.Hash().Hex()).Msg("Broadcasting Staking Tx") utils.Logger().Info().Str("Hash", newStakingTx.Hash().Hex()).Msg("Broadcasting Staking Tx")
node.tryBroadcastStaking(newStakingTx) node.tryBroadcastStaking(newStakingTx)
} }
return err
}
return nil return nil
} }
@ -275,15 +283,20 @@ func (node *Node) AddPendingStakingTransaction(
func (node *Node) AddPendingTransaction(newTx *types.Transaction) error { func (node *Node) AddPendingTransaction(newTx *types.Transaction) error {
if newTx.ShardID() == node.NodeConfig.ShardID { if newTx.ShardID() == node.NodeConfig.ShardID {
errs := node.addPendingTransactions(types.Transactions{newTx}) errs := node.addPendingTransactions(types.Transactions{newTx})
var err error
for i := range errs { for i := range errs {
if errs[i] != nil { if errs[i] != nil {
utils.Logger().Info().Err(errs[i]).Msg("[AddPendingTransaction] Failed adding new transaction") utils.Logger().Info().Err(errs[i]).Msg("[AddPendingTransaction] Failed adding new transaction")
return errs[i] err = errs[i]
break
} }
} }
if err == nil || node.BroadcastInvalidTx {
utils.Logger().Info().Str("Hash", newTx.Hash().Hex()).Msg("Broadcasting Tx") utils.Logger().Info().Str("Hash", newTx.Hash().Hex()).Msg("Broadcasting Tx")
node.tryBroadcast(newTx) node.tryBroadcast(newTx)
} }
return err
}
return nil return nil
} }

@ -17,6 +17,7 @@ import (
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/node/worker" "github.com/harmony-one/harmony/node/worker"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
lru "github.com/hashicorp/golang-lru"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -382,11 +383,7 @@ func (node *Node) CalculateResponse(request *downloader_pb.DownloaderRequest, in
var hash common.Hash var hash common.Hash
for _, bytes := range request.Hashes { for _, bytes := range request.Hashes {
hash.SetBytes(bytes) hash.SetBytes(bytes)
blockHeader := node.Blockchain().GetHeaderByHash(hash) encodedBlockHeader, err := node.getEncodedBlockHeaderByHash(hash)
if blockHeader == nil {
continue
}
encodedBlockHeader, err := rlp.EncodeToBytes(blockHeader)
if err == nil { if err == nil {
response.Payload = append(response.Payload, encodedBlockHeader) response.Payload = append(response.Payload, encodedBlockHeader)
@ -397,11 +394,7 @@ func (node *Node) CalculateResponse(request *downloader_pb.DownloaderRequest, in
var hash common.Hash var hash common.Hash
for _, bytes := range request.Hashes { for _, bytes := range request.Hashes {
hash.SetBytes(bytes) hash.SetBytes(bytes)
block := node.Blockchain().GetBlockByHash(hash) encodedBlock, err := node.getEncodedBlockByHash(hash)
if block == nil {
continue
}
encodedBlock, err := rlp.EncodeToBytes(block)
if err == nil { if err == nil {
response.Payload = append(response.Payload, encodedBlock) response.Payload = append(response.Payload, encodedBlock)
@ -478,3 +471,49 @@ func (node *Node) CalculateResponse(request *downloader_pb.DownloaderRequest, in
} }
return response, nil return response, nil
} }
const (
headerCacheSize = 10000
blockCacheSize = 10000
)
var (
// Cached fields for block header and block requests
headerReqCache, _ = lru.New(headerCacheSize)
blockReqCache, _ = lru.New(blockCacheSize)
errHeaderNotExist = errors.New("header not exist")
errBlockNotExist = errors.New("block not exist")
)
func (node *Node) getEncodedBlockHeaderByHash(hash common.Hash) ([]byte, error) {
if b, ok := headerReqCache.Get(hash); ok {
return b.([]byte), nil
}
h := node.Blockchain().GetHeaderByHash(hash)
if h == nil {
return nil, errHeaderNotExist
}
b, err := rlp.EncodeToBytes(h)
if err != nil {
return nil, err
}
headerReqCache.Add(hash, b)
return b, nil
}
func (node *Node) getEncodedBlockByHash(hash common.Hash) ([]byte, error) {
if b, ok := blockReqCache.Get(hash); ok {
return b.([]byte), nil
}
blk := node.Blockchain().GetBlockByHash(hash)
if blk == nil {
return nil, errBlockNotExist
}
b, err := rlp.EncodeToBytes(blk)
if err != nil {
return nil, err
}
blockReqCache.Add(hash, b)
return b, nil
}

@ -18,7 +18,7 @@ TRACEPTR=
VERBOSE= VERBOSE=
GO_GCFLAGS="all=-c 2" GO_GCFLAGS="all=-c 2"
DEBUG=false DEBUG=false
STATIC=false STATIC=true
unset -v progdir unset -v progdir
case "${0}" in case "${0}" in
@ -62,6 +62,7 @@ OPTIONS:
-t full analysis on {pointer} build option (default: $TRACEPTR) -t full analysis on {pointer} build option (default: $TRACEPTR)
-v verbose build process (default: $VERBOSE) -v verbose build process (default: $VERBOSE)
-s build static linux executable (default: $STATIC) -s build static linux executable (default: $STATIC)
-S build non-static linux executable
ACTION: ACTION:
@ -257,6 +258,7 @@ while getopts "hp:a:o:b:f:rtvsdS" option; do
v) VERBOSE='-v -x' ;; v) VERBOSE='-v -x' ;;
d) DEBUG=true ;; d) DEBUG=true ;;
s) STATIC=true ;; s) STATIC=true ;;
S) STATIC=false ;;
esac esac
done done

@ -200,6 +200,7 @@ options:
-r address start a pprof profiling server listening on the specified address -r address start a pprof profiling server listening on the specified address
-I use statically linked Harmony binary (default: true) -I use statically linked Harmony binary (default: true)
-R tracefile enable p2p trace using tracefile (default: off) -R tracefile enable p2p trace using tracefile (default: off)
-l limit broadcasting of invalid transactions (default: off)
-L log_level logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: $log_level) -L log_level logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: $log_level)
examples: examples:
@ -251,7 +252,7 @@ usage() {
BUCKET=pub.harmony.one BUCKET=pub.harmony.one
OS=$(uname -s) OS=$(uname -s)
unset start_clean loop run_as_root blspass do_not_download download_only network node_type shard_id db_file_to_dl unset start_clean loop run_as_root blspass do_not_download download_only network node_type shard_id broadcast_invalid_tx
unset upgrade_rel public_rpc staking_mode pub_port multi_key blsfolder blacklist verify TRACEFILE minpeers max_bls_keys_per_node log_level unset upgrade_rel public_rpc staking_mode pub_port multi_key blsfolder blacklist verify TRACEFILE minpeers max_bls_keys_per_node log_level
start_clean=false start_clean=false
loop=true loop=true
@ -272,13 +273,14 @@ static=true
verify=false verify=false
minpeers=6 minpeers=6
max_bls_keys_per_node=10 max_bls_keys_per_node=10
broadcast_invalid_tx=true
log_level=3 log_level=3
${BLSKEYFILE=} ${BLSKEYFILE=}
${TRACEFILE=} ${TRACEFILE=}
unset OPTIND OPTARG opt unset OPTIND OPTARG opt
OPTIND=1 OPTIND=1
while getopts :1chk:sSp:dDN:T:i:a:U:PvVyzn:MAIB:r:Y:f:R:m:L: opt while getopts :1chk:sSp:dDN:T:i:U:PvVyzn:MAIB:r:Y:f:R:m:L:l opt
do do
case "${opt}" in case "${opt}" in
'?') usage "unrecognized option -${OPTARG}";; '?') usage "unrecognized option -${OPTARG}";;
@ -300,7 +302,6 @@ do
T) node_type="${OPTARG}";; T) node_type="${OPTARG}";;
i) shard_id="${OPTARG}";; i) shard_id="${OPTARG}";;
I) static=true;; I) static=true;;
a) db_file_to_dl="${OPTARG}";;
U) upgrade_rel="${OPTARG}";; U) upgrade_rel="${OPTARG}";;
P) public_rpc=true;; P) public_rpc=true;;
B) blacklist="${OPTARG}";; B) blacklist="${OPTARG}";;
@ -314,6 +315,7 @@ do
y) staking_mode=false;; y) staking_mode=false;;
A) archival=true;; A) archival=true;;
R) TRACEFILE="${OPTARG}";; R) TRACEFILE="${OPTARG}";;
l) broadcast_invalid_tx=false;;
L) log_level="${OPTARG}";; L) log_level="${OPTARG}";;
*) err 70 "unhandled option -${OPTARG}";; # EX_SOFTWARE *) err 70 "unhandled option -${OPTARG}";; # EX_SOFTWARE
esac esac
@ -342,26 +344,16 @@ mainnet)
dns_zone=t.hmny.io dns_zone=t.hmny.io
syncdir=mainnet.min syncdir=mainnet.min
;; ;;
testnet) # TODO: update Testnet configs once LRTN is upgraded testnet)
bootnodes=( bootnodes=(
/ip4/54.218.73.167/tcp/9876/p2p/QmWBVCPXQmc2ULigm3b9ayCZa15gj25kywiQQwPhHCZeXj /ip4/54.86.126.90/tcp/9850/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv
/ip4/18.232.171.117/tcp/9876/p2p/QmfJ71Eb7XTDs8hX2vPJ8un4L7b7RiDk6zCzWVxLXGA6MA /ip4/52.40.84.2/tcp/9850/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29
) )
REL=testnet REL=testnet
network_type=testnet network_type=testnet
dns_zone=p.hmny.io dns_zone=b.hmny.io
syncdir=lrtn syncdir=lrtn
;; ;;
tnet)
bootnodes=(
/ip4/54.86.126.90/tcp/9889/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv
/ip4/52.40.84.2/tcp/9889/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29
)
REL=tnet
network_type=testnet
dns_zone=tn.hmny.io
syncdir=tnet
;;
staking) staking)
bootnodes=( bootnodes=(
/ip4/54.86.126.90/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv /ip4/54.86.126.90/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv
@ -391,16 +383,6 @@ stn|stress|stressnet)
dns_zone=stn.hmny.io dns_zone=stn.hmny.io
syncdir=stn syncdir=stn
;; ;;
devnet)
bootnodes=(
/ip4/54.86.126.90/tcp/9870/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv
/ip4/52.40.84.2/tcp/9870/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29
)
REL=devnet
network_type=devnet
dns_zone=pga.hmny.io
syncdir=devnet
;;
*) *)
err 64 "${network}: invalid network" err 64 "${network}: invalid network"
;; ;;
@ -767,7 +749,8 @@ read_bls_pass() {
unset -v passphrase unset -v passphrase
read -rsp "Enter passphrase for the BLS key file $f: " passphrase read -rsp "Enter passphrase for the BLS key file $f: " passphrase
echo ${passphrase} | tee $passfile echo ${passphrase} | tee $passfile
echo "Passphrase is temporarely saved to: $passfile" chmod og-wr $passfile
echo "Passphrase is temporarily saved to: $passfile"
prompt_save=true prompt_save=true
fi fi
done done
@ -853,6 +836,7 @@ do
-blacklist="${blacklist}" -blacklist="${blacklist}"
-min_peers="${minpeers}" -min_peers="${minpeers}"
-max_bls_keys_per_node="${max_bls_keys_per_node}" -max_bls_keys_per_node="${max_bls_keys_per_node}"
-broadcast_invalid_tx="${broadcast_invalid_tx}"
-verbosity="${log_level}" -verbosity="${log_level}"
) )
args+=( args+=(

@ -470,10 +470,7 @@ func checkIncWrapperVerified(snapWrapper, curWrapper *staking.ValidatorWrapper)
} }
snapToSign := snapWrapper.Counters.NumBlocksToSign snapToSign := snapWrapper.Counters.NumBlocksToSign
curToSign := curWrapper.Counters.NumBlocksToSign curToSign := curWrapper.Counters.NumBlocksToSign
if curToSign.Cmp(new(big.Int).Add(snapToSign, common.Big1)) != 0 { return curToSign.Cmp(new(big.Int).Add(snapToSign, common.Big1)) == 0
return false
}
return true
} }
// checkIncWrapperMissing is the compare function to check whether validator wrapper // checkIncWrapperMissing is the compare function to check whether validator wrapper
@ -486,10 +483,7 @@ func checkIncWrapperMissing(snapWrapper, curWrapper *staking.ValidatorWrapper) b
} }
snapToSign := snapWrapper.Counters.NumBlocksToSign snapToSign := snapWrapper.Counters.NumBlocksToSign
curToSign := curWrapper.Counters.NumBlocksToSign curToSign := curWrapper.Counters.NumBlocksToSign
if curToSign.Cmp(new(big.Int).Add(snapToSign, common.Big1)) != 0 { return curToSign.Cmp(new(big.Int).Add(snapToSign, common.Big1)) == 0
return false
}
return true
} }
type computeEPOSTestCtx struct { type computeEPOSTestCtx struct {

@ -21,6 +21,19 @@ const (
Banned Banned
) )
func (e Eligibility) String() string {
switch e {
case Active:
return "active"
case Inactive:
return "inactive"
case Banned:
return doubleSigningBanned
default:
return "unknown"
}
}
// Candidacy is a more semantically meaningful // Candidacy is a more semantically meaningful
// value that is derived from core protocol logic but // value that is derived from core protocol logic but
// meant more for the presentation of user, like at RPC // meant more for the presentation of user, like at RPC

@ -630,7 +630,6 @@ func (tc *applyTestCase) makeData(t *testing.T) {
} }
} }
tc.stateSnap = tc.state.Copy() tc.stateSnap = tc.state.Copy()
return
} }
func (tc *applyTestCase) apply() { func (tc *applyTestCase) apply() {
@ -781,7 +780,7 @@ func makeVoteData(kp blsKeyPair, block *types.Block) Vote {
} }
func makeTestAddress(item interface{}) common.Address { func makeTestAddress(item interface{}) common.Address {
s := fmt.Sprintf("harmony.one.%s", item) s := fmt.Sprintf("harmony.one.%v", item)
return common.BytesToAddress([]byte(s)) return common.BytesToAddress([]byte(s))
} }

@ -11,10 +11,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const (
fakeChainErrEpoch = 1
)
var ( var (
errFakeChainUnexpectEpoch = errors.New("epoch not expected") errFakeChainUnexpectEpoch = errors.New("epoch not expected")
) )

@ -8,8 +8,8 @@ import (
) )
// CopyValidatorWrapper deep copies staking.ValidatorWrapper // CopyValidatorWrapper deep copies staking.ValidatorWrapper
func CopyValidatorWrapper(w *staking.ValidatorWrapper) *staking.ValidatorWrapper { func CopyValidatorWrapper(w staking.ValidatorWrapper) staking.ValidatorWrapper {
cp := &staking.ValidatorWrapper{ cp := staking.ValidatorWrapper{
Validator: CopyValidator(w.Validator), Validator: CopyValidator(w.Validator),
Delegations: CopyDelegations(w.Delegations), Delegations: CopyDelegations(w.Delegations),
} }

@ -14,14 +14,6 @@ import (
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
) )
var (
zeroDec = numeric.ZeroDec()
oneThirdDec = numeric.NewDecWithPrec(33, 2)
halfDec = numeric.NewDecWithPrec(5, 1)
twoThirdDec = numeric.NewDecWithPrec(66, 2)
oneDec = numeric.OneDec()
)
var ( var (
testPub = shard.BLSPublicKey{1} testPub = shard.BLSPublicKey{1}
) )
@ -35,9 +27,9 @@ func TestCopyValidatorWrapper(t *testing.T) {
{staking.ValidatorWrapper{}}, {staking.ValidatorWrapper{}},
} }
for i, test := range tests { for i, test := range tests {
cp := CopyValidatorWrapper(&test.w) cp := CopyValidatorWrapper(test.w)
if err := assertValidatorWrapperDeepCopy(*cp, test.w); err != nil { if err := assertValidatorWrapperDeepCopy(cp, test.w); err != nil {
t.Errorf("Test %v: %v", i, err) t.Errorf("Test %v: %v", i, err)
} }
} }
@ -255,13 +247,6 @@ func assertCommissionDeepCopy(c1, c2 staking.Commission) error {
return nil return nil
} }
func assertCommissionRatesDeepCopy(cr1, cr2 staking.CommissionRates) error {
if !reflect.DeepEqual(cr1, cr2) {
return errors.New("not deep equal")
}
return assertCommissionRatesCopy(cr1, cr2)
}
func assertCommissionRatesCopy(cr1, cr2 staking.CommissionRates) error { func assertCommissionRatesCopy(cr1, cr2 staking.CommissionRates) error {
if err := assertDecCopy(cr1.Rate, cr2.Rate); err != nil { if err := assertDecCopy(cr1.Rate, cr2.Rate); err != nil {
return fmt.Errorf("rate: %v", err) return fmt.Errorf("rate: %v", err)

@ -0,0 +1,209 @@
package staketest
import (
"fmt"
"math/big"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
// CheckValidatorWrapperEqual checks the equality of staking.ValidatorWrapper. If not equal, an
// error is returned. Note nil pointer is treated as zero in this compare function.
func CheckValidatorWrapperEqual(w1, w2 staking.ValidatorWrapper) error {
if err := checkValidatorWrapperEqual(w1, w2); err != nil {
return fmt.Errorf("wrapper%v", err)
}
return nil
}
// CheckValidatorEqual checks the equality of validator. If not equal, an
// error is returned. Note nil pointer is treated as zero in this compare function.
func CheckValidatorEqual(v1, v2 staking.Validator) error {
if err := checkValidatorEqual(v1, v2); err != nil {
return fmt.Errorf("validator%v", err)
}
return nil
}
func checkValidatorWrapperEqual(w1, w2 staking.ValidatorWrapper) error {
if err := checkValidatorEqual(w1.Validator, w2.Validator); err != nil {
return fmt.Errorf(".Validator%v", err)
}
if err := checkDelegationsEqual(w1.Delegations, w2.Delegations); err != nil {
return fmt.Errorf(".Delegations%v", err)
}
if err := checkBigIntEqual(w1.Counters.NumBlocksToSign, w2.Counters.NumBlocksToSign); err != nil {
return fmt.Errorf("..Counters.NumBlocksToSign %v", err)
}
if err := checkBigIntEqual(w1.Counters.NumBlocksSigned, w2.Counters.NumBlocksSigned); err != nil {
return fmt.Errorf("..Counters.NumBlocksSigned %v", err)
}
if err := checkBigIntEqual(w1.BlockReward, w2.BlockReward); err != nil {
return fmt.Errorf(".BlockReward %v", err)
}
return nil
}
func checkValidatorEqual(v1, v2 staking.Validator) error {
if v1.Address != v2.Address {
return fmt.Errorf(".Address not equal: %x / %x", v1.Address, v2.Address)
}
if err := checkPubKeysEqual(v1.SlotPubKeys, v2.SlotPubKeys); err != nil {
return fmt.Errorf(".SlotPubKeys%v", err)
}
if err := checkBigIntEqual(v1.LastEpochInCommittee, v2.LastEpochInCommittee); err != nil {
return fmt.Errorf(".LastEpochInCommittee %v", err)
}
if err := checkBigIntEqual(v1.MinSelfDelegation, v2.MinSelfDelegation); err != nil {
return fmt.Errorf(".MinSelfDelegation %v", err)
}
if err := checkBigIntEqual(v1.MaxTotalDelegation, v2.MaxTotalDelegation); err != nil {
return fmt.Errorf(".MaxTotalDelegation %v", err)
}
if v1.Status != v2.Status {
return fmt.Errorf(".Status not equal: %v / %v", v1.Status, v2.Status)
}
if err := checkCommissionEqual(v1.Commission, v2.Commission); err != nil {
return fmt.Errorf(".Commission%v", err)
}
if err := checkDescriptionEqual(v1.Description, v2.Description); err != nil {
return fmt.Errorf(".Description%v", err)
}
if err := checkBigIntEqual(v1.CreationHeight, v2.CreationHeight); err != nil {
return fmt.Errorf(".CreationHeight %v", err)
}
return nil
}
func checkDelegationsEqual(ds1, ds2 staking.Delegations) error {
if len(ds1) != len(ds2) {
return fmt.Errorf(".len not equal: %v / %v", len(ds1), len(ds2))
}
for i := range ds1 {
if err := checkDelegationEqual(ds1[i], ds2[i]); err != nil {
return fmt.Errorf("[%v]%v", i, err)
}
}
return nil
}
func checkDelegationEqual(d1, d2 staking.Delegation) error {
if d1.DelegatorAddress != d2.DelegatorAddress {
return fmt.Errorf(".DelegatorAddress not equal: %x / %x",
d1.DelegatorAddress, d2.DelegatorAddress)
}
if err := checkBigIntEqual(d1.Amount, d2.Amount); err != nil {
return fmt.Errorf(".Amount %v", err)
}
if err := checkBigIntEqual(d1.Reward, d2.Reward); err != nil {
return fmt.Errorf(".Reward %v", err)
}
if err := checkUndelegationsEqual(d1.Undelegations, d2.Undelegations); err != nil {
return fmt.Errorf(".Undelegations%v", err)
}
return nil
}
func checkUndelegationsEqual(uds1, uds2 staking.Undelegations) error {
if len(uds1) != len(uds2) {
return fmt.Errorf(".len not equal: %v / %v", len(uds1), len(uds2))
}
for i := range uds1 {
if err := checkUndelegationEqual(uds1[i], uds2[i]); err != nil {
return fmt.Errorf("[%v]%v", i, err)
}
}
return nil
}
func checkUndelegationEqual(ud1, ud2 staking.Undelegation) error {
if err := checkBigIntEqual(ud1.Amount, ud2.Amount); err != nil {
return fmt.Errorf(".Amount %v", err)
}
if err := checkBigIntEqual(ud1.Epoch, ud2.Epoch); err != nil {
return fmt.Errorf(".Epoch %v", err)
}
return nil
}
func checkPubKeysEqual(pubs1, pubs2 []shard.BLSPublicKey) error {
if len(pubs1) != len(pubs2) {
return fmt.Errorf(".len not equal: %v / %v", len(pubs1), len(pubs2))
}
for i := range pubs1 {
if pubs1[i] != pubs2[i] {
return fmt.Errorf("[%v] not equal: %x / %x", i, pubs1[i], pubs2[i])
}
}
return nil
}
func checkDescriptionEqual(d1, d2 staking.Description) error {
if d1.Name != d2.Name {
return fmt.Errorf(".Name not equal: %v / %v", d1.Name, d2.Name)
}
if d1.Identity != d2.Identity {
return fmt.Errorf(".Identity not equal: %v / %v", d1.Identity, d2.Identity)
}
if d1.Website != d2.Website {
return fmt.Errorf(".Website not equal: %v / %v", d1.Website, d2.Website)
}
if d1.Details != d2.Details {
return fmt.Errorf(".Details not equal: %v / %v", d1.Details, d2.Details)
}
if d1.SecurityContact != d2.SecurityContact {
return fmt.Errorf(".SecurityContact not equal: %v / %v", d1.SecurityContact, d2.SecurityContact)
}
return nil
}
func checkCommissionEqual(c1, c2 staking.Commission) error {
if err := checkCommissionRateEqual(c1.CommissionRates, c2.CommissionRates); err != nil {
return fmt.Errorf(".CommissionRate%v", err)
}
if err := checkBigIntEqual(c1.UpdateHeight, c2.UpdateHeight); err != nil {
return fmt.Errorf(".UpdateHeight %v", err)
}
return nil
}
func checkCommissionRateEqual(cr1, cr2 staking.CommissionRates) error {
if err := checkDecEqual(cr1.Rate, cr2.Rate); err != nil {
return fmt.Errorf(".Rate %v", err)
}
if err := checkDecEqual(cr1.MaxChangeRate, cr2.MaxChangeRate); err != nil {
return fmt.Errorf(".MaxChangeRate %v", err)
}
if err := checkDecEqual(cr1.MaxRate, cr2.MaxRate); err != nil {
return fmt.Errorf(".MaxRate %v", err)
}
return nil
}
func checkDecEqual(d1, d2 numeric.Dec) error {
if d1.IsNil() {
d1 = numeric.ZeroDec()
}
if d2.IsNil() {
d2 = numeric.ZeroDec()
}
if !d1.Equal(d2) {
return fmt.Errorf("not equal: %v / %v", d1, d2)
}
return nil
}
func checkBigIntEqual(i1, i2 *big.Int) error {
if i1 == nil {
i1 = big.NewInt(0)
}
if i2 == nil {
i2 = big.NewInt(0)
}
if i1.Cmp(i2) != 0 {
return fmt.Errorf("not equal: %v / %v", i1, i2)
}
return nil
}

@ -0,0 +1,37 @@
package staketest
import (
"testing"
staking "github.com/harmony-one/harmony/staking/types"
)
func TestCheckValidatorWrapperEqual(t *testing.T) {
tests := []struct {
w1, w2 staking.ValidatorWrapper
}{
{vWrapperPrototype, vWrapperPrototype},
{makeZeroValidatorWrapper(), makeZeroValidatorWrapper()},
{staking.ValidatorWrapper{}, staking.ValidatorWrapper{}},
}
for i, test := range tests {
if err := CheckValidatorWrapperEqual(test.w1, test.w2); err != nil {
t.Errorf("Test %v: %v", i, err)
}
}
}
func TestCheckValidatorEqual(t *testing.T) {
tests := []struct {
v1, v2 staking.Validator
}{
{validatorPrototype, validatorPrototype},
{makeZeroValidator(), makeZeroValidator()},
{staking.Validator{}, staking.Validator{}},
}
for i, test := range tests {
if err := CheckValidatorEqual(test.v1, test.v2); err != nil {
t.Errorf("Test %v: %v", i, err)
}
}
}

@ -0,0 +1,118 @@
package staketest
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/staking/effective"
staking "github.com/harmony-one/harmony/staking/types"
)
var (
oneBig = big.NewInt(1e18)
tenKOnes = new(big.Int).Mul(big.NewInt(10000), oneBig)
twentyKOnes = new(big.Int).Mul(big.NewInt(20000), oneBig)
hundredKOnes = new(big.Int).Mul(big.NewInt(100000), oneBig)
// DefaultDelAmount is the default delegation amount
DefaultDelAmount = new(big.Int).Set(twentyKOnes)
// DefaultMinSelfDel is the default value of MinSelfDelegation
DefaultMinSelfDel = new(big.Int).Set(tenKOnes)
// DefaultMaxTotalDel is the default value of MaxTotalDelegation
DefaultMaxTotalDel = new(big.Int).Set(hundredKOnes)
)
var (
vWrapperPrototype = func() staking.ValidatorWrapper {
w := staking.ValidatorWrapper{
Validator: validatorPrototype,
Delegations: staking.Delegations{
staking.Delegation{
DelegatorAddress: validatorPrototype.Address,
Amount: DefaultDelAmount,
Reward: common.Big0,
Undelegations: staking.Undelegations{},
},
},
BlockReward: common.Big0,
}
w.Counters.NumBlocksToSign = common.Big0
w.Counters.NumBlocksSigned = common.Big0
return w
}()
validatorPrototype = staking.Validator{
Address: common.Address{},
SlotPubKeys: []shard.BLSPublicKey{shard.BLSPublicKey{}},
LastEpochInCommittee: common.Big0,
MinSelfDelegation: DefaultMinSelfDel,
MaxTotalDelegation: DefaultMaxTotalDel,
Status: effective.Active,
Commission: commission,
Description: description,
CreationHeight: common.Big0,
}
commissionRates = staking.CommissionRates{
Rate: numeric.NewDecWithPrec(5, 1),
MaxRate: numeric.NewDecWithPrec(9, 1),
MaxChangeRate: numeric.NewDecWithPrec(3, 1),
}
commission = staking.Commission{
CommissionRates: commissionRates,
UpdateHeight: common.Big0,
}
description = staking.Description{
Name: "SuperHero",
Identity: "YouWouldNotKnow",
Website: "Secret Website",
SecurityContact: "LicenseToKill",
Details: "blah blah blah",
}
)
// GetDefaultValidator return the default staking.Validator for testing
func GetDefaultValidator() staking.Validator {
return CopyValidator(validatorPrototype)
}
// GetDefaultValidatorWithAddr return the default staking.Validator with the
// given validator address and bls keys
func GetDefaultValidatorWithAddr(addr common.Address, pubs []shard.BLSPublicKey) staking.Validator {
v := CopyValidator(validatorPrototype)
v.Address = addr
if pubs != nil {
v.SlotPubKeys = make([]shard.BLSPublicKey, len(pubs))
copy(v.SlotPubKeys, pubs)
} else {
v.SlotPubKeys = nil
}
return v
}
// GetDefaultValidatorWrapper return the default staking.ValidatorWrapper for testing
func GetDefaultValidatorWrapper() staking.ValidatorWrapper {
return CopyValidatorWrapper(vWrapperPrototype)
}
// GetDefaultValidatorWrapperWithAddr return the default staking.ValidatorWrapper
// with the given validator address and bls keys.
func GetDefaultValidatorWrapperWithAddr(addr common.Address, pubs []shard.BLSPublicKey) staking.ValidatorWrapper {
w := CopyValidatorWrapper(vWrapperPrototype)
w.Address = addr
if pubs != nil {
w.SlotPubKeys = make([]shard.BLSPublicKey, len(pubs))
copy(w.SlotPubKeys, pubs)
} else {
w.SlotPubKeys = nil
}
w.Delegations[0].DelegatorAddress = addr
return w
}

@ -0,0 +1,79 @@
package staketest
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/shard"
)
func TestGetDefaultValidator(t *testing.T) {
v := GetDefaultValidator()
if err := assertValidatorDeepCopy(v, validatorPrototype); err != nil {
t.Error(err)
}
}
func TestGetDefaultValidatorWrapper(t *testing.T) {
w := GetDefaultValidatorWrapper()
if err := assertValidatorWrapperDeepCopy(w, vWrapperPrototype); err != nil {
t.Error(err)
}
}
func TestGetDefaultValidatorWithAddr(t *testing.T) {
tests := []struct {
addr common.Address
keys []shard.BLSPublicKey
}{
{
addr: common.BigToAddress(common.Big1),
keys: []shard.BLSPublicKey{{1}, {}},
},
{
addr: common.Address{},
keys: make([]shard.BLSPublicKey, 0),
},
{},
}
for i, test := range tests {
v := GetDefaultValidatorWithAddr(test.addr, test.keys)
exp := CopyValidator(validatorPrototype)
exp.Address = test.addr
exp.SlotPubKeys = test.keys
if err := assertValidatorDeepCopy(v, exp); err != nil {
t.Errorf("Test %v: %v", i, err)
}
}
}
func TestGetDefaultValidatorWrapperWithAddr(t *testing.T) {
tests := []struct {
addr common.Address
keys []shard.BLSPublicKey
}{
{
addr: common.BigToAddress(common.Big1),
keys: []shard.BLSPublicKey{{1}, {}},
},
{
addr: common.Address{},
keys: make([]shard.BLSPublicKey, 0),
},
{},
}
for i, test := range tests {
v := GetDefaultValidatorWrapperWithAddr(test.addr, test.keys)
exp := CopyValidatorWrapper(vWrapperPrototype)
exp.Address = test.addr
exp.SlotPubKeys = test.keys
exp.Delegations[0].DelegatorAddress = test.addr
if err := assertValidatorWrapperDeepCopy(v, exp); err != nil {
t.Errorf("Test %v: %v", i, err)
}
}
}

@ -138,8 +138,8 @@ type CurrentEpochPerformance struct {
CurrentSigningPercentage Computed `json:"current-epoch-signing-percent"` CurrentSigningPercentage Computed `json:"current-epoch-signing-percent"`
} }
// ValidatorRPCEnchanced contains extra information for RPC consumer // ValidatorRPCEnhanced contains extra information for RPC consumer
type ValidatorRPCEnchanced struct { type ValidatorRPCEnhanced struct {
Wrapper ValidatorWrapper `json:"validator"` Wrapper ValidatorWrapper `json:"validator"`
Performance *CurrentEpochPerformance `json:"current-epoch-performance"` Performance *CurrentEpochPerformance `json:"current-epoch-performance"`
ComputedMetrics *ValidatorStats `json:"metrics"` ComputedMetrics *ValidatorStats `json:"metrics"`
@ -148,6 +148,7 @@ type ValidatorRPCEnchanced struct {
EPoSStatus string `json:"epos-status"` EPoSStatus string `json:"epos-status"`
EPoSWinningStake *numeric.Dec `json:"epos-winning-stake"` EPoSWinningStake *numeric.Dec `json:"epos-winning-stake"`
BootedStatus *string `json:"booted-status"` BootedStatus *string `json:"booted-status"`
ActiveStatus string `json:"active-status"`
Lifetime *AccumulatedOverLifetime `json:"lifetime"` Lifetime *AccumulatedOverLifetime `json:"lifetime"`
} }

@ -27,9 +27,6 @@ var (
var ( var (
zeroDec = numeric.ZeroDec() zeroDec = numeric.ZeroDec()
oneThirdDec = numeric.NewDecWithPrec(33, 2)
halfDec = numeric.NewDecWithPrec(5, 1)
twoThirdDec = numeric.NewDecWithPrec(66, 2)
oneDec = numeric.OneDec() oneDec = numeric.OneDec()
) )

@ -64,6 +64,9 @@ func DoPost(url string, record interface{}) (*ReportResult, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body) result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
anon := ReportResult{} anon := ReportResult{}
if err := json.Unmarshal(result, &anon); err != nil { if err := json.Unmarshal(result, &anon); err != nil {
return nil, err return nil, err

Loading…
Cancel
Save