Merge pull request #1723 from rlan35/mainnet_release_1012_diff

Mainnet release 1012 diff
pull/1726/head testnet-20191013.0
Eugene Kim 5 years ago committed by GitHub
commit 2601066112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/client/txgen/main.go
  2. 79
      cmd/client/wallet/main.go
  3. 51
      cmd/client/wallet/validation_test.go
  4. 44
      cmd/staking/root.go
  5. 27
      consensus/README.md
  6. 113
      consensus/consensus.go
  7. 1
      consensus/consensus_v2.go
  8. 12
      consensus/engine/consensus_engine.go
  9. 35
      contracts/structs/structs.go
  10. 6
      core/block_validator.go
  11. 16
      core/blockchain.go
  12. 10
      core/chain_makers.go
  13. 4
      core/gaspool.go
  14. 2
      core/numeric/decimal.go
  15. 2
      core/numeric/decimal_test.go
  16. 39
      core/resharding.go
  17. 18
      core/state_processor.go
  18. 8
      core/state_transition.go
  19. 65
      core/tx_pool.go
  20. 22
      core/tx_pool_test.go
  21. 15
      core/types/block.go
  22. 10
      core/values/blockchain.go
  23. 38
      core/values/error.go
  24. 1
      crypto/vdf/vdf.go
  25. 1
      drand/drand_leader.go
  26. 12
      internal/chain/engine.go
  27. 2
      internal/chain/reward.go
  28. 1
      internal/hmyapi/filters/api.go
  29. 6
      internal/hmyapi/transactionpool.go
  30. 3
      internal/memprofiling/lib.go
  31. 2
      internal/profiler/profiler.go
  32. 63
      msgq/msgq.go
  33. 94
      msgq/msgq_test.go
  34. 74
      node/node.go
  35. 5
      node/node_cross_shard.go
  36. 78
      node/node_handler.go
  37. 3
      node/node_newblock.go
  38. 10
      node/node_resharding.go
  39. 3
      node/node_syncing.go
  40. 72
      node/worker/worker.go
  41. 5
      shard/shard_state.go
  42. 14
      staking/types/commission.go
  43. 5
      staking/types/messages.go
  44. 4
      staking/types/sign.go
  45. 5
      staking/types/transaction.go
  46. 24
      staking/types/validator.go

@ -88,7 +88,6 @@ func setUpTXGen() *node.Node {
shardID := *shardIDFlag shardID := *shardIDFlag
selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: peerPubKey} selfPeer := p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: peerPubKey}
gsif, err := consensus.NewGenesisStakeInfoFinder()
// Nodes containing blockchain data to mirror the shards' data in the network // Nodes containing blockchain data to mirror the shards' data in the network
myhost, err := p2pimpl.NewHost(&selfPeer, nodePriKey) myhost, err := p2pimpl.NewHost(&selfPeer, nodePriKey)
@ -103,7 +102,6 @@ func setUpTXGen() *node.Node {
chainDBFactory := &shardchain.MemDBFactory{} chainDBFactory := &shardchain.MemDBFactory{}
txGen := node.New(myhost, consensusObj, chainDBFactory, false) //Changed it : no longer archival node. txGen := node.New(myhost, consensusObj, chainDBFactory, false) //Changed it : no longer archival node.
txGen.Client = client.NewClient(txGen.GetHost(), uint32(shardID)) txGen.Client = client.NewClient(txGen.GetHost(), uint32(shardID))
consensusObj.SetStakeInfoFinder(gsif)
consensusObj.ChainReader = txGen.Blockchain() consensusObj.ChainReader = txGen.Blockchain()
consensusObj.PublicKeys = nil consensusObj.PublicKeys = nil
genesisShardingConfig := core.ShardingSchedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch)) genesisShardingConfig := core.ShardingSchedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch))

@ -10,14 +10,15 @@ import (
"math/rand" "math/rand"
"os" "os"
"path" "path"
"regexp"
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/fatih/color" "github.com/fatih/color"
ffi_bls "github.com/harmony-one/bls/ffi/go/bls" ffi_bls "github.com/harmony-one/bls/ffi/go/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/accounts" "github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/accounts/keystore" "github.com/harmony-one/harmony/accounts/keystore"
"github.com/harmony-one/harmony/api/client" "github.com/harmony-one/harmony/api/client"
@ -520,7 +521,6 @@ func showAllBalances(sender, receiver string, fromS, toS int) {
} }
} }
} }
} }
func processBalancesCommand() { func processBalancesCommand() {
@ -532,6 +532,13 @@ func processBalancesCommand() {
showAllBalances("", "", -1, -1) showAllBalances("", "", -1, -1)
} else { } else {
address := common2.ParseAddr(*balanceAddressPtr) address := common2.ParseAddr(*balanceAddressPtr)
valid, errorMessage := validateAddress(*balanceAddressPtr, address, "")
if !valid && len(errorMessage) > 0 {
fmt.Println(errorMessage)
return
}
fmt.Printf("Account: %s:\n", common2.MustAddressToBech32(address)) fmt.Printf("Account: %s:\n", common2.MustAddressToBech32(address))
for shardID, balanceNonce := range FetchBalance(address) { for shardID, balanceNonce := range FetchBalance(address) {
if balanceNonce != nil { if balanceNonce != nil {
@ -553,6 +560,12 @@ func formatAddressCommand() {
fmt.Println("Please specify the --address to show formats for.") fmt.Println("Please specify the --address to show formats for.")
} else { } else {
address := common2.ParseAddr(*formatAddressPtr) address := common2.ParseAddr(*formatAddressPtr)
valid, errorMessage := validateAddress(*formatAddressPtr, address, "")
if !valid && len(errorMessage) > 0 {
fmt.Println(errorMessage)
return
}
fmt.Printf("account address in Bech32: %s\n", common2.MustAddressToBech32(address)) fmt.Printf("account address in Bech32: %s\n", common2.MustAddressToBech32(address))
fmt.Printf("account address in Base16 (deprecated): %s\n", address.Hex()) fmt.Printf("account address in Base16 (deprecated): %s\n", address.Hex())
@ -665,6 +678,13 @@ func processGetFreeToken() {
fmt.Println("Error: --address is required") fmt.Println("Error: --address is required")
} else { } else {
address := common2.ParseAddr(*freeTokenAddressPtr) address := common2.ParseAddr(*freeTokenAddressPtr)
valid, errorMessage := validateAddress(*freeTokenAddressPtr, address, "")
if !valid && len(errorMessage) > 0 {
fmt.Println(errorMessage)
return
}
GetFreeToken(address) GetFreeToken(address)
} }
} }
@ -690,24 +710,34 @@ func processTransferCommand() {
return return
} }
if shardID == -1 || toShardID == -1 { if !validShard(shardID, walletProfile.Shards) {
fmt.Println("Please specify the shard ID for the transfer (e.g. --shardID=0)") fmt.Println("Please specify a valid sender shard ID for the transfer (e.g. --shardID=0)")
return
}
if !validShard(toShardID, walletProfile.Shards) {
fmt.Println("Please specify a valid receiver shard ID for the transfer (e.g. --toShardID=0)")
return return
} }
if amount <= 0 { if amount <= 0 {
fmt.Println("Please specify positive amount to transfer") fmt.Println("Please specify positive amount to transfer")
return return
} }
receiverAddress := common2.ParseAddr(receiver) senderAddress := common2.ParseAddr(sender)
if len(receiverAddress) != 20 { valid, errorMessage := validateAddress(sender, senderAddress, "sender")
fmt.Println("The receiver address is not valid.")
if !valid && len(errorMessage) > 0 {
fmt.Println(errorMessage)
return return
} }
senderAddress := common2.ParseAddr(sender) receiverAddress := common2.ParseAddr(receiver)
if len(senderAddress) != 20 { valid, errorMessage = validateAddress(receiver, receiverAddress, "receiver")
fmt.Println("The sender address is not valid.")
if !valid && len(errorMessage) > 0 {
fmt.Println(errorMessage)
return return
} }
@ -956,3 +986,32 @@ func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uin
return nil return nil
} }
var (
addressValidationRegexp = regexp.MustCompile(`(?i)^(one[a-zA-Z0-9]{39})|(0x[a-fA-F0-9]{40})`)
)
func validateAddress(address string, commonAddress common.Address, addressType string) (bool, string) {
var valid = true
var errorMessage string
if len(addressType) > 0 {
addressType = fmt.Sprintf("%s ", addressType)
}
matches := addressValidationRegexp.FindAllStringSubmatch(address, -1)
if len(matches) == 0 || len(commonAddress) != 20 {
valid = false
errorMessage = fmt.Sprintf("The %saddress you supplied (%s) is in an invalid format. Please provide a valid address.", addressType, address)
}
return valid, errorMessage
}
func validShard(shardID int, shardCount int) bool {
if shardID < 0 || shardID > (shardCount-1) {
return false
}
return true
}

@ -0,0 +1,51 @@
package main
import (
"testing"
"github.com/harmony-one/harmony/internal/common"
)
func TestIsValidAddress(t *testing.T) {
tests := []struct {
str string
exp bool
}{
{"one1ay37rp2pc3kjarg7a322vu3sa8j9puahg679z3", true},
{"0x7c41E0668B551f4f902cFaec05B5Bdca68b124CE", true},
{"onefoofoo", false},
{"0xbarbar", false},
{"dsasdadsasaadsas", false},
{"32312123213213212321", false},
}
for _, test := range tests {
valid, _ := validateAddress(test.str, common.ParseAddr(test.str), "sender")
if valid != test.exp {
t.Errorf("validateAddress(\"%s\") returned %v, expected %v", test.str, valid, test.exp)
}
}
}
func TestIsValidShard(t *testing.T) {
readProfile("local")
tests := []struct {
shardID int
exp bool
}{
{0, true},
{1, true},
{-1, false},
{99, false},
}
for _, test := range tests {
valid := validShard(test.shardID, walletProfile.Shards)
if valid != test.exp {
t.Errorf("validShard(%d) returned %v, expected %v", test.shardID, valid, test.exp)
}
}
}

@ -57,29 +57,29 @@ func (s *staker) run(cmd *cobra.Command, args []string) error {
p.DeserializeHexStr(testBLSPubKey) p.DeserializeHexStr(testBLSPubKey)
pub := shard.BlsPublicKey{} pub := shard.BlsPublicKey{}
pub.FromLibBLSPublicKey(p) pub.FromLibBLSPublicKey(p)
return staking.DirectiveNewValidator, staking.NewValidator{ // return staking.DirectiveNewValidator, staking.NewValidator{
Description: staking.Description{ // Description: staking.Description{
Name: "something", // Name: "something",
Identity: "something else", // Identity: "something else",
Website: "some site, harmony.one", // Website: "some site, harmony.one",
SecurityContact: "mr.smith", // SecurityContact: "mr.smith",
Details: "blah blah details", // Details: "blah blah details",
}, // },
CommissionRates: staking.CommissionRates{ // CommissionRates: staking.CommissionRates{
Rate: staking.NewDec(100), // Rate: staking.NewDec(100),
MaxRate: staking.NewDec(150), // MaxRate: staking.NewDec(150),
MaxChangeRate: staking.NewDec(5), // MaxChangeRate: staking.NewDec(5),
}, // },
MinSelfDelegation: big.NewInt(10), // MinSelfDelegation: big.NewInt(10),
StakingAddress: common.Address(dAddr), // StakingAddress: common.Address(dAddr),
PubKey: pub, // PubKey: pub,
Amount: big.NewInt(100), // Amount: big.NewInt(100),
}
// return message.DirectiveDelegate, message.Delegate{
// common.Address(dAddr),
// common.Address(dAddr),
// big.NewInt(10),
// } // }
return staking.DirectiveDelegate, staking.Delegate{
common.Address(dAddr),
common.Address(dAddr),
big.NewInt(10),
}
} }
stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker) stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker)

@ -1,8 +1,13 @@
Consensus package includes the Harmony BFT consensus protocol code, which uses BLS-based multi-signature to cosign the new block. The details are in Harmony's new [consensus protocol design](https://talk.harmony.one/t/bls-based-practical-bft-consensus/131). Consensus package includes the Harmony BFT consensus protocol code, which uses BLS-based
multi-signature to cosign the new block. The details are
in Harmony's new [consensus protocol design](https://talk.harmony.one/t/bls-based-practical-bft-consensus/131).
## Introduction to Harmony BFT with BLS signatures ## Introduction to Harmony BFT with BLS signatures
Harmony BFT consensus protocol consist of normal mode and view changing mode which is same as the PBFT(practical byzantine fault tolerance) protocol. The difference is we use the BLS aggregated signature to reduce O(N^2) communications to O(N), which is more efficient and scalable to traditional PBFT. For brevity, we will still call the whole process as PBFT. Harmony BFT consensus protocol consist of normal mode and view changing mode which is same
as the PBFT(practical byzantine fault tolerance) protocol. The difference is we use the
BLS aggregated signature to reduce O(N^2) communications to O(N), which is more efficient
and scalable to traditional PBFT. For brevity, we will still call the whole process as PBFT.
### Normal mode ### Normal mode
@ -81,21 +86,3 @@ func (consensus *Consensus) Start(stopChan chan struct{}, stoppedChan chan struc
``` ```

@ -8,19 +8,13 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
bls_cosi "github.com/harmony-one/harmony/crypto/bls" bls_cosi "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/genesis"
"github.com/harmony-one/harmony/internal/memprofiling" "github.com/harmony-one/harmony/internal/memprofiling"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
) )
const ( const (
@ -150,9 +144,6 @@ type Consensus struct {
// MessageSender takes are of sending consensus message and the corresponding retry logic. // MessageSender takes are of sending consensus message and the corresponding retry logic.
msgSender *MessageSender msgSender *MessageSender
// Staking information finder
stakeInfoFinder StakeInfoFinder
// Used to convey to the consensus main loop that block syncing has finished. // Used to convey to the consensus main loop that block syncing has finished.
syncReadyChan chan struct{} syncReadyChan chan struct{}
// Used to convey to the consensus main loop that node is out of sync // Used to convey to the consensus main loop that node is out of sync
@ -171,18 +162,6 @@ func (consensus *Consensus) SetCommitDelay(delay time.Duration) {
consensus.delayCommit = delay consensus.delayCommit = delay
} }
// StakeInfoFinder returns the stake information finder instance this
// consensus uses, e.g. for block reward distribution.
func (consensus *Consensus) StakeInfoFinder() StakeInfoFinder {
return consensus.stakeInfoFinder
}
// SetStakeInfoFinder sets the stake information finder instance this
// consensus uses, e.g. for block reward distribution.
func (consensus *Consensus) SetStakeInfoFinder(stakeInfoFinder StakeInfoFinder) {
consensus.stakeInfoFinder = stakeInfoFinder
}
// DisableViewChangeForTestingOnly makes the receiver not propose view // DisableViewChangeForTestingOnly makes the receiver not propose view
// changes when it should, e.g. leader timeout. // changes when it should, e.g. leader timeout.
// //
@ -235,19 +214,6 @@ func (consensus *Consensus) GetBlockReward() *big.Int {
return consensus.lastBlockReward return consensus.lastBlockReward
} }
// StakeInfoFinder finds the staking account for the given consensus key.
type StakeInfoFinder interface {
// FindStakeInfoByNodeKey returns a list of staking information matching
// the given node key. Caller may modify the returned slice of StakeInfo
// struct pointers, but must not modify the StakeInfo structs themselves.
FindStakeInfoByNodeKey(key *bls.PublicKey) []*structs.StakeInfo
// FindStakeInfoByAccount returns a list of staking information matching
// the given account. Caller may modify the returned slice of StakeInfo
// struct pointers, but must not modify the StakeInfo structs themselves.
FindStakeInfoByAccount(addr common.Address) []*structs.StakeInfo
}
// New creates a new Consensus object // New creates a new Consensus object
// TODO: put shardId into chain reader's chain config // TODO: put shardId into chain reader's chain config
func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKey) (*Consensus, error) { func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKey) (*Consensus, error) {
@ -255,19 +221,15 @@ func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKe
consensus.host = host consensus.host = host
consensus.msgSender = NewMessageSender(host) consensus.msgSender = NewMessageSender(host)
consensus.blockNumLowChan = make(chan struct{}) consensus.blockNumLowChan = make(chan struct{})
// pbft related // pbft related
consensus.PbftLog = NewPbftLog() consensus.PbftLog = NewPbftLog()
consensus.phase = Announce consensus.phase = Announce
consensus.mode = PbftMode{mode: Normal} consensus.mode = PbftMode{mode: Normal}
// pbft timeout // pbft timeout
consensus.consensusTimeout = createTimeout() consensus.consensusTimeout = createTimeout()
consensus.prepareSigs = map[string]*bls.Sign{} consensus.prepareSigs = map[string]*bls.Sign{}
consensus.commitSigs = map[string]*bls.Sign{} consensus.commitSigs = map[string]*bls.Sign{}
consensus.CommitteePublicKeys = make(map[string]bool) consensus.CommitteePublicKeys = make(map[string]bool)
consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader) consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader)
if blsPriKey != nil { if blsPriKey != nil {
@ -283,90 +245,15 @@ func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKe
// as it was displayed on explorer as Height right now // as it was displayed on explorer as Height right now
consensus.viewID = 0 consensus.viewID = 0
consensus.ShardID = ShardID consensus.ShardID = ShardID
consensus.MsgChan = make(chan []byte) consensus.MsgChan = make(chan []byte)
consensus.syncReadyChan = make(chan struct{}) consensus.syncReadyChan = make(chan struct{})
consensus.syncNotReadyChan = make(chan struct{}) consensus.syncNotReadyChan = make(chan struct{})
consensus.commitFinishChan = make(chan uint64) consensus.commitFinishChan = make(chan uint64)
consensus.ReadySignal = make(chan struct{}) consensus.ReadySignal = make(chan struct{})
consensus.lastBlockReward = big.NewInt(0) consensus.lastBlockReward = big.NewInt(0)
// channel for receiving newly generated VDF // channel for receiving newly generated VDF
consensus.RndChannel = make(chan [vdfAndSeedSize]byte) consensus.RndChannel = make(chan [vdfAndSeedSize]byte)
consensus.uniqueIDInstance = utils.GetUniqueValidatorIDInstance() consensus.uniqueIDInstance = utils.GetUniqueValidatorIDInstance()
memprofiling.GetMemProfiling().Add("consensus.pbftLog", consensus.PbftLog) memprofiling.GetMemProfiling().Add("consensus.pbftLog", consensus.PbftLog)
return &consensus, nil return &consensus, nil
} }
// GenesisStakeInfoFinder is a stake info finder implementation using only
// genesis accounts.
// When used for block reward, it rewards only foundational nodes.
type GenesisStakeInfoFinder struct {
byNodeKey map[shard.BlsPublicKey][]*structs.StakeInfo
byAccount map[common.Address][]*structs.StakeInfo
}
// FindStakeInfoByNodeKey returns the genesis account matching the given node
// key, as a single-item StakeInfo list.
// It returns nil if the key is not a genesis node key.
func (f *GenesisStakeInfoFinder) FindStakeInfoByNodeKey(
key *bls.PublicKey,
) []*structs.StakeInfo {
var pk shard.BlsPublicKey
if err := pk.FromLibBLSPublicKey(key); err != nil {
utils.Logger().Warn().Err(err).Msg("cannot convert BLS public key")
return nil
}
l, _ := f.byNodeKey[pk]
return l
}
// FindStakeInfoByAccount returns the genesis account matching the given
// address, as a single-item StakeInfo list.
// It returns nil if the address is not a genesis account.
func (f *GenesisStakeInfoFinder) FindStakeInfoByAccount(
addr common.Address,
) []*structs.StakeInfo {
l, _ := f.byAccount[addr]
return l
}
// NewGenesisStakeInfoFinder returns a stake info finder that can look up
// genesis nodes.
func NewGenesisStakeInfoFinder() (*GenesisStakeInfoFinder, error) {
f := &GenesisStakeInfoFinder{
byNodeKey: make(map[shard.BlsPublicKey][]*structs.StakeInfo),
byAccount: make(map[common.Address][]*structs.StakeInfo),
}
for idx, account := range genesis.HarmonyAccounts {
pub := &bls.PublicKey{}
pub.DeserializeHexStr(account.BlsPublicKey)
var blsPublicKey shard.BlsPublicKey
if err := blsPublicKey.FromLibBLSPublicKey(pub); err != nil {
return nil, ctxerror.New("cannot convert BLS public key",
"accountIndex", idx,
).WithCause(err)
}
addressBytes, err := hexutil.Decode(account.Address)
if err != nil {
return nil, ctxerror.New("cannot decode account address",
"accountIndex", idx,
).WithCause(err)
}
var address common.Address
address.SetBytes(addressBytes)
stakeInfo := &structs.StakeInfo{
Account: address,
BlsPublicKey: blsPublicKey,
BlockNum: common.Big0,
LockPeriodCount: big.NewInt(0x7fffffffffffffff),
Amount: common.Big0,
}
f.byNodeKey[blsPublicKey] = append(f.byNodeKey[blsPublicKey], stakeInfo)
f.byAccount[address] = append(f.byAccount[address], stakeInfo)
}
return f, nil
}

@ -1269,6 +1269,7 @@ func (consensus *Consensus) GenerateVdfAndProof(newBlock *types.Block, vrfBlockN
Int("Num of VRF", len(vrfBlockNumbers)). Int("Num of VRF", len(vrfBlockNumbers)).
Msg("[ConsensusMainLoop] VDF computation started") Msg("[ConsensusMainLoop] VDF computation started")
// TODO ek – limit concurrency
go func() { go func() {
vdf := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed) vdf := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed)
outputChannel := vdf.GetOutputChannel() outputChannel := vdf.GetOutputChannel()

@ -4,12 +4,12 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"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/internal/params"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
) )
// ChainReader defines a small collection of methods needed to access the local // ChainReader defines a small collection of methods needed to access the local
@ -77,8 +77,12 @@ type Engine interface {
// and assembles the final block. // and assembles the final block.
// Note: The block header and state database might be updated to reflect any // Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards). // consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction, Finalize(
receipts []*types.Receipt, outcxs []*types.CXReceipt, incxs []*types.CXReceiptsProof) (*types.Block, error) chain ChainReader, header *block.Header, state *state.DB,
txs []*types.Transaction,
stkgTxs []*staking.StakingTransaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt,
incxs []*types.CXReceiptsProof) (*types.Block, error)
// Seal generates a new sealing request for the given input block and pushes // Seal generates a new sealing request for the given input block and pushes
// the result into the given channel. // the result into the given channel.

@ -1,35 +0,0 @@
package structs
import (
"math/big"
"github.com/harmony-one/harmony/shard"
"github.com/ethereum/go-ethereum/common"
)
// StakeInfoReturnValue is the struct for the return value of listLockedAddresses func in stake contract.
type StakeInfoReturnValue struct {
LockedAddresses []common.Address
BlsPubicKeys1 [][32]byte
BlsPubicKeys2 [][32]byte
BlsPubicKeys3 [][32]byte // TODO: remove third part as know we use 48 bytes pub key
BlockNums []*big.Int
LockPeriodCounts []*big.Int // The number of locking period the token will be locked.
Amounts []*big.Int
}
// StakeInfo stores the staking information for a staker.
type StakeInfo struct {
Account common.Address
BlsPublicKey shard.BlsPublicKey
BlockNum *big.Int
LockPeriodCount *big.Int // The number of locking period the token will be locked.
Amount *big.Int
}
// PlayersInfo stores the result of getPlayers.
type PlayersInfo struct {
Players []common.Address
Balances []*big.Int
}

@ -24,11 +24,11 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/internal/ctxerror"
consensus_engine "github.com/harmony-one/harmony/consensus/engine" consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"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/values"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
) )
@ -58,7 +58,7 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
func (v *BlockValidator) ValidateBody(block *types.Block) error { func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Check whether the block's known, and if not, that it's linkable // Check whether the block's known, and if not, that it's linkable
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return ErrKnownBlock return values.ErrKnownBlock
} }
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {

@ -35,19 +35,18 @@ import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/internal/params"
lru "github.com/hashicorp/golang-lru"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
consensus_engine "github.com/harmony-one/harmony/consensus/engine" consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core/rawdb" "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/values"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
lru "github.com/hashicorp/golang-lru"
) )
var ( var (
@ -1250,7 +1249,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
err = bc.Validator().ValidateBody(block) err = bc.Validator().ValidateBody(block)
} }
switch { switch {
case err == ErrKnownBlock: case err == values.ErrKnownBlock:
// Block and state both already known. However if the current block is below // Block and state both already known. However if the current block is below
// this number we did a rollback and we should reimport it nonetheless. // this number we did a rollback and we should reimport it nonetheless.
if bc.CurrentBlock().NumberU64() >= block.NumberU64() { if bc.CurrentBlock().NumberU64() >= block.NumberU64() {
@ -1909,15 +1908,12 @@ func (bc *BlockChain) GetVrfByNumber(number uint64) []byte {
// GetShardState returns the shard state for the given epoch, // GetShardState returns the shard state for the given epoch,
// creating one if needed. // creating one if needed.
func (bc *BlockChain) GetShardState( func (bc *BlockChain) GetShardState(epoch *big.Int) (shard.State, error) {
epoch *big.Int,
stakeInfo *map[common.Address]*structs.StakeInfo,
) (shard.State, error) {
shardState, err := bc.ReadShardState(epoch) shardState, err := bc.ReadShardState(epoch)
if err == nil { // TODO ek – distinguish ErrNotFound if err == nil { // TODO ek – distinguish ErrNotFound
return shardState, err return shardState, err
} }
shardState, err = CalculateNewShardState(bc, epoch, stakeInfo) shardState, err = CalculateNewShardState(bc, epoch)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -23,15 +23,15 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
consensus_engine "github.com/harmony-one/harmony/consensus/engine" consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"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"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
) )
// BlockGen creates blocks for testing. // BlockGen creates blocks for testing.
@ -46,6 +46,7 @@ type BlockGen struct {
gasPool *GasPool gasPool *GasPool
txs []*types.Transaction txs []*types.Transaction
stkTxs staking.StakingTransactions
receipts []*types.Receipt receipts []*types.Receipt
uncles []*block.Header uncles []*block.Header
@ -184,9 +185,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if gen != nil { if gen != nil {
gen(i, b) gen(i, b)
} }
if b.engine != nil { if b.engine != nil {
// Finalize and seal the block // Finalize and seal the block
block, err := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.receipts, nil, nil) block, err := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.stkTxs, b.receipts, nil, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }

@ -19,6 +19,8 @@ package core
import ( import (
"fmt" "fmt"
"math" "math"
"github.com/harmony-one/harmony/core/values"
) )
// GasPool tracks the amount of gas available during execution of the transactions // GasPool tracks the amount of gas available during execution of the transactions
@ -38,7 +40,7 @@ func (gp *GasPool) AddGas(amount uint64) *GasPool {
// available and returns an error otherwise. // available and returns an error otherwise.
func (gp *GasPool) SubGas(amount uint64) error { func (gp *GasPool) SubGas(amount uint64) error {
if uint64(*gp) < amount { if uint64(*gp) < amount {
return ErrGasLimitReached return values.ErrGasLimitReached
} }
*(*uint64)(gp) -= amount *(*uint64)(gp) -= amount
return nil return nil

@ -1,4 +1,4 @@
package types package numeric
import ( import (
"encoding/json" "encoding/json"

@ -1,4 +1,4 @@
package types package numeric
import ( import (
"math/big" "math/big"

@ -9,8 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/contracts/structs"
common2 "github.com/harmony-one/harmony/internal/common" common2 "github.com/harmony-one/harmony/internal/common"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
@ -158,10 +156,7 @@ func GetShardingStateFromBlockChain(bc *BlockChain, epoch *big.Int) (*ShardingSt
} }
// CalculateNewShardState get sharding state from previous epoch and calculate sharding state for new epoch // CalculateNewShardState get sharding state from previous epoch and calculate sharding state for new epoch
func CalculateNewShardState( func CalculateNewShardState(bc *BlockChain, epoch *big.Int) (shard.State, error) {
bc *BlockChain, epoch *big.Int,
stakeInfo *map[common.Address]*structs.StakeInfo,
) (shard.State, error) {
if epoch.Cmp(big.NewInt(GenesisEpoch)) == 0 { if epoch.Cmp(big.NewInt(GenesisEpoch)) == 0 {
return CalculateInitShardState(), nil return CalculateInitShardState(), nil
} }
@ -171,42 +166,10 @@ func CalculateNewShardState(
return nil, ctxerror.New("cannot retrieve previous sharding state"). return nil, ctxerror.New("cannot retrieve previous sharding state").
WithCause(err) WithCause(err)
} }
newNodeList := ss.UpdateShardingState(stakeInfo)
utils.Logger().Info().Float64("percentage", CuckooRate).Msg("Cuckoo Rate") utils.Logger().Info().Float64("percentage", CuckooRate).Msg("Cuckoo Rate")
ss.Reshard(newNodeList, CuckooRate)
return ss.shardState, nil return ss.shardState, nil
} }
// UpdateShardingState remove the unstaked nodes and returns the newly staked node Ids.
func (ss *ShardingState) UpdateShardingState(stakeInfo *map[common.Address]*structs.StakeInfo) []shard.NodeID {
oldBlsPublicKeys := make(map[shard.BlsPublicKey]bool) // map of bls public keys
for _, shard := range ss.shardState {
newNodeList := shard.NodeList
for _, nodeID := range shard.NodeList {
oldBlsPublicKeys[nodeID.BlsPublicKey] = true
_, ok := (*stakeInfo)[nodeID.EcdsaAddress]
if ok {
// newNodeList = append(newNodeList, nodeID)
} else {
// TODO: Remove the node if it's no longer staked
}
}
shard.NodeList = newNodeList
}
newAddresses := []shard.NodeID{}
for addr, info := range *stakeInfo {
_, ok := oldBlsPublicKeys[info.BlsPublicKey]
if !ok {
newAddresses = append(newAddresses, shard.NodeID{
EcdsaAddress: addr,
BlsPublicKey: info.BlsPublicKey,
})
}
}
return newAddresses
}
// TODO ek – shardingSchedule should really be part of a general-purpose network // TODO ek – shardingSchedule should really be part of a general-purpose network
// configuration. We are OK for the time being, // configuration. We are OK for the time being,
// until the day we should let one node process join multiple networks. // until the day we should let one node process join multiple networks.

@ -21,7 +21,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
consensus_engine "github.com/harmony-one/harmony/consensus/engine" consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/state"
@ -30,6 +29,7 @@ import (
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
staking "github.com/harmony-one/harmony/staking/types"
) )
// StateProcessor is a basic Processor, which takes care of transitioning // StateProcessor is a basic Processor, which takes care of transitioning
@ -94,7 +94,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C
} }
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
_, err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), receipts, outcxs, incxs) _, err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.StakingTransactions(), receipts, outcxs, incxs)
if err != nil { if err != nil {
return nil, nil, nil, 0, ctxerror.New("cannot finalize block").WithCause(err) return nil, nil, nil, 0, ctxerror.New("cannot finalize block").WithCause(err)
} }
@ -180,6 +180,18 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
return receipt, cxReceipt, gas, err return receipt, cxReceipt, gas, err
} }
// ApplyStakingTransaction attempts to apply a staking transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the staking transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
// staking transaction will use the code field in the account to store the staking information
// TODO chao: Add receipts for staking tx
func ApplyStakingTransaction(
config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.DB,
header *block.Header, tx *staking.StakingTransaction, usedGas *uint64, cfg vm.Config) (receipt *types.Receipt, gasUsed uint64, oops error) {
return nil, 0, nil
}
// ApplyIncomingReceipt will add amount into ToAddress in the receipt // ApplyIncomingReceipt will add amount into ToAddress in the receipt
func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *block.Header, cxp *types.CXReceiptsProof) error { func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *block.Header, cxp *types.CXReceiptsProof) error {
if cxp == nil { if cxp == nil {
@ -197,7 +209,7 @@ func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *bloc
db.CreateAccount(*cx.To) db.CreateAccount(*cx.To)
} }
db.AddBalance(*cx.To, cx.Amount) db.AddBalance(*cx.To, cx.Amount)
db.IntermediateRoot(config.IsS3(header.Epoch())).Bytes() db.IntermediateRoot(config.IsS3(header.Epoch()))
} }
return nil return nil
} }

@ -22,9 +22,9 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/core/values"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
) )
@ -171,9 +171,9 @@ func (st *StateTransition) preCheck() error {
nonce := st.state.GetNonce(st.msg.From()) nonce := st.state.GetNonce(st.msg.From())
if nonce < st.msg.Nonce() { if nonce < st.msg.Nonce() {
return ErrNonceTooHigh return values.ErrNonceTooHigh
} else if nonce > st.msg.Nonce() { } else if nonce > st.msg.Nonce() {
return ErrNonceTooLow return values.ErrNonceTooLow
} }
} }
return st.buyGas() return st.buyGas()

@ -18,7 +18,6 @@ package core
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"math" "math"
"math/big" "math/big"
@ -30,11 +29,11 @@ import (
"github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"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/values"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
) )
@ -43,44 +42,6 @@ const (
chainHeadChanSize = 10 chainHeadChanSize = 10
) )
var (
// ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender = errors.New("invalid sender")
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow = errors.New("nonce too low")
// ErrUnderpriced is returned if a transaction's gas price is below the minimum
// configured for the transaction pool.
ErrUnderpriced = errors.New("transaction underpriced")
// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
// with a different one without the required price bump.
ErrReplaceUnderpriced = errors.New("replacement transaction underpriced")
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit")
// ErrNegativeValue is a sanity error to ensure noone is able to specify a
// transaction with a negative value.
ErrNegativeValue = errors.New("negative value")
// ErrOversizedData is returned if the input data of a transaction is greater
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.
ErrOversizedData = errors.New("oversized data")
)
var ( var (
evictionInterval = time.Minute // Time interval to check for evictable transactions evictionInterval = time.Minute // Time interval to check for evictable transactions
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
@ -602,42 +563,42 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 { if tx.Size() > 32*1024 {
return ErrOversizedData return values.ErrOversizedData
} }
// Transactions can't be negative. This may never happen using RLP decoded // Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC. // transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 { if tx.Value().Sign() < 0 {
return ErrNegativeValue return values.ErrNegativeValue
} }
// Ensure the transaction doesn't exceed the current block limit gas. // Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() { if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit return values.ErrGasLimit
} }
// Make sure the transaction is signed properly // Make sure the transaction is signed properly
from, err := types.Sender(pool.signer, tx) from, err := types.Sender(pool.signer, tx)
if err != nil { if err != nil {
return ErrInvalidSender return values.ErrInvalidSender
} }
// Drop non-local transactions under our own minimal accepted gas price // Drop non-local transactions under our own minimal accepted gas price
local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
return ErrUnderpriced return values.ErrUnderpriced
} }
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
if pool.currentState.GetNonce(from) > tx.Nonce() { if pool.currentState.GetNonce(from) > tx.Nonce() {
return ErrNonceTooLow return values.ErrNonceTooLow
} }
// Transactor should have enough funds to cover the costs // Transactor should have enough funds to cover the costs
// cost == V + GP * GL // cost == V + GP * GL
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
return ErrInsufficientFunds return values.ErrInsufficientFunds
} }
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
if err != nil { if err != nil {
return err return err
} }
if tx.Gas() < intrGas { if tx.Gas() < intrGas {
return ErrIntrinsicGas return values.ErrIntrinsicGas
} }
return nil return nil
} }
@ -673,7 +634,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
Str("price", tx.GasPrice().String()). Str("price", tx.GasPrice().String()).
Msg("Discarding underpriced transaction") Msg("Discarding underpriced transaction")
underpricedTxCounter.Inc(1) underpricedTxCounter.Inc(1)
return false, ErrUnderpriced return false, values.ErrUnderpriced
} }
// New transaction is better than our worse ones, make room for it // New transaction is better than our worse ones, make room for it
drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals)
@ -693,7 +654,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
inserted, old := list.Add(tx, pool.config.PriceBump) inserted, old := list.Add(tx, pool.config.PriceBump)
if !inserted { if !inserted {
pendingDiscardCounter.Inc(1) pendingDiscardCounter.Inc(1)
return false, ErrReplaceUnderpriced return false, values.ErrReplaceUnderpriced
} }
// New transaction is better, replace old one // New transaction is better, replace old one
if old != nil { if old != nil {
@ -759,7 +720,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er
if !inserted { if !inserted {
// An older transaction was better, discard this // An older transaction was better, discard this
queuedDiscardCounter.Inc(1) queuedDiscardCounter.Inc(1)
return false, ErrReplaceUnderpriced return false, values.ErrReplaceUnderpriced
} }
// Discard any previous transaction and mark this // Discard any previous transaction and mark this
if old != nil { if old != nil {

@ -30,11 +30,11 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
blockfactory "github.com/harmony-one/harmony/block/factory" blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/common/denominations"
"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/values"
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
) )
@ -235,27 +235,27 @@ func TestInvalidTransactions(t *testing.T) {
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
pool.currentState.AddBalance(from, big.NewInt(1)) pool.currentState.AddBalance(from, big.NewInt(1))
if err := pool.AddRemote(tx); err != ErrInsufficientFunds { if err := pool.AddRemote(tx); err != values.ErrInsufficientFunds {
t.Error("expected", ErrInsufficientFunds) t.Error("expected", values.ErrInsufficientFunds)
} }
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
pool.currentState.AddBalance(from, balance) pool.currentState.AddBalance(from, balance)
if err := pool.AddRemote(tx); err != ErrIntrinsicGas { if err := pool.AddRemote(tx); err != values.ErrIntrinsicGas {
t.Error("expected", ErrIntrinsicGas, "got", err) t.Error("expected", values.ErrIntrinsicGas, "got", err)
} }
pool.currentState.SetNonce(from, 1) pool.currentState.SetNonce(from, 1)
pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff))
tx = transaction(0, 100000, key) tx = transaction(0, 100000, key)
if err := pool.AddRemote(tx); err != ErrNonceTooLow { if err := pool.AddRemote(tx); err != values.ErrNonceTooLow {
t.Error("expected", ErrNonceTooLow) t.Error("expected", values.ErrNonceTooLow)
} }
tx = transaction(1, 100000, key) tx = transaction(1, 100000, key)
pool.gasPrice = big.NewInt(1000) pool.gasPrice = big.NewInt(1000)
if err := pool.AddRemote(tx); err != ErrUnderpriced { if err := pool.AddRemote(tx); err != values.ErrUnderpriced {
t.Error("expected", ErrUnderpriced, "got", err) t.Error("expected", values.ErrUnderpriced, "got", err)
} }
if err := pool.AddLocal(tx); err != nil { if err := pool.AddLocal(tx); err != nil {
t.Error("expected", nil, "got", err) t.Error("expected", nil, "got", err)
@ -325,8 +325,8 @@ func TestTransactionNegativeValue(t *testing.T) {
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, 0, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, 0, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
pool.currentState.AddBalance(from, big.NewInt(1)) pool.currentState.AddBalance(from, big.NewInt(1))
if err := pool.AddRemote(tx); err != ErrNegativeValue { if err := pool.AddRemote(tx); err != values.ErrNegativeValue {
t.Error("expected", ErrNegativeValue, "got", err) t.Error("expected", values.ErrNegativeValue, "got", err)
} }
} }

@ -30,10 +30,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/taggedrlp"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory" blockfactory "github.com/harmony-one/harmony/block/factory"
v0 "github.com/harmony-one/harmony/block/v0" v0 "github.com/harmony-one/harmony/block/v0"
@ -42,6 +38,10 @@ import (
"github.com/harmony-one/harmony/crypto/hash" "github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/harmony-one/taggedrlp"
"github.com/pkg/errors"
"github.com/rs/zerolog"
) )
// Constants for block. // Constants for block.
@ -181,7 +181,7 @@ func init() {
BodyRegistry.MustRegister("v1", new(BodyV1)) BodyRegistry.MustRegister("v1", new(BodyV1))
} }
// Block represents an entire block in the Ethereum blockchain. // Block represents an entire block in the Harmony blockchain.
type Block struct { type Block struct {
header *block.Header header *block.Header
uncles []*block.Header uncles []*block.Header
@ -347,6 +347,11 @@ func (b *Block) Transactions() Transactions {
return b.transactions return b.transactions
} }
// StakingTransactions returns stakingTransactions.
func (b *Block) StakingTransactions() staking.StakingTransactions {
return staking.StakingTransactions{}
}
// IncomingReceipts returns verified outgoing receipts // IncomingReceipts returns verified outgoing receipts
func (b *Block) IncomingReceipts() CXReceiptsProofs { func (b *Block) IncomingReceipts() CXReceiptsProofs {
return b.incomingReceipts return b.incomingReceipts

@ -0,0 +1,10 @@
package values
const (
// BeaconChainShardID is the ShardID of the BeaconChain
BeaconChainShardID = 0
// VotingPowerReduceBlockThreshold roughly corresponds to 3 hours
VotingPowerReduceBlockThreshold = 1350
// VotingPowerFullReduce roughly corresponds to 12 hours
VotingPowerFullReduce = 4 * VotingPowerReduceBlockThreshold
)

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core package values
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
@ -31,6 +31,10 @@ var (
// ErrBlacklistedHash is returned if a block to import is on the blacklist. // ErrBlacklistedHash is returned if a block to import is on the blacklist.
ErrBlacklistedHash = errors.New("blacklisted hash") ErrBlacklistedHash = errors.New("blacklisted hash")
// ErrNonceTooLow is returned if the nonce of a transaction is lower than the
// one present in the local chain.
ErrNonceTooLow = errors.New("nonce too low")
// ErrNonceTooHigh is returned if the nonce of a transaction is higher than the // ErrNonceTooHigh is returned if the nonce of a transaction is higher than the
// next one expected based on the local chain. // next one expected based on the local chain.
ErrNonceTooHigh = errors.New("nonce too high") ErrNonceTooHigh = errors.New("nonce too high")
@ -40,4 +44,36 @@ var (
// ErrInvalidChainID when ChainID of signer does not match that of running node // ErrInvalidChainID when ChainID of signer does not match that of running node
ErrInvalidChainID = errors.New("invalid chain id for signer") ErrInvalidChainID = errors.New("invalid chain id for signer")
// ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender = errors.New("invalid sender")
// ErrUnderpriced is returned if a transaction's gas price is below the minimum
// configured for the transaction pool.
ErrUnderpriced = errors.New("transaction underpriced")
// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
// with a different one without the required price bump.
ErrReplaceUnderpriced = errors.New("replacement transaction underpriced")
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit")
// ErrNegativeValue is a sanity error to ensure noone is able to specify a
// transaction with a negative value.
ErrNegativeValue = errors.New("negative value")
// ErrOversizedData is returned if the input data of a transaction is greater
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.
ErrOversizedData = errors.New("oversized data")
) )

@ -37,6 +37,7 @@ func (vdf *VDF) Execute() {
tempResult = sha3.Sum256(tempResult[:]) tempResult = sha3.Sum256(tempResult[:])
} }
vdf.output = tempResult vdf.output = tempResult
// TODO ek – limit concurrency
go func() { go func() {
vdf.outputChan <- vdf.output vdf.outputChan <- vdf.output
}() }()

@ -38,6 +38,7 @@ func (dRand *DRand) WaitForEpochBlock(blockChannel chan *types.Block, stopChan c
zeros := [32]byte{} zeros := [32]byte{}
if core.IsEpochBlock(newBlock) && !bytes.Equal(pRnd[:], zeros[:]) { if core.IsEpochBlock(newBlock) && !bytes.Equal(pRnd[:], zeros[:]) {
// The epoch block should contain the randomness preimage pRnd // The epoch block should contain the randomness preimage pRnd
// TODO ek – limit concurrency
go func() { go func() {
vdf := vdf.New(vdfDifficulty, pRnd) vdf := vdf.New(vdfDifficulty, pRnd)
outputChannel := vdf.GetOutputChannel() outputChannel := vdf.GetOutputChannel()

@ -6,9 +6,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine" "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
@ -17,6 +14,9 @@ import (
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
) )
type engineImpl struct{} type engineImpl struct{}
@ -149,7 +149,11 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header)
// Finalize implements Engine, accumulating the block rewards, // Finalize implements Engine, accumulating the block rewards,
// setting the final state and assembling the block. // setting the final state and assembling the block.
func (e *engineImpl) Finalize(chain engine.ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction, receipts []*types.Receipt, outcxs []*types.CXReceipt, incxs []*types.CXReceiptsProof) (*types.Block, error) { func (e *engineImpl) Finalize(
chain engine.ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction,
stkgTxs []*staking.StakingTransaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt,
incxs []*types.CXReceiptsProof) (*types.Block, error) {
// Accumulate any block and uncle rewards and commit the final state root // Accumulate any block and uncle rewards and commit the final state root
// Header seems complete, assemble into a block and return // Header seems complete, assemble into a block and return
if err := AccumulateRewards(chain, state, header); err != nil { if err := AccumulateRewards(chain, state, header); err != nil {

@ -5,7 +5,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/common/denominations" "github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/consensus/engine" "github.com/harmony-one/harmony/consensus/engine"
@ -85,6 +84,7 @@ func AccumulateRewards(
accounts = append(accounts, member.EcdsaAddress) accounts = append(accounts, member.EcdsaAddress)
} }
} }
numAccounts := big.NewInt(int64(len(accounts))) numAccounts := big.NewInt(int64(len(accounts)))
last := new(big.Int) last := new(big.Int)
for i, account := range accounts { for i, account := range accounts {

@ -60,6 +60,7 @@ func NewPublicFilterAPI(backend Backend, lightMode bool) *PublicFilterAPI {
// timeoutLoop runs every 5 minutes and deletes filters that have not been recently used. // timeoutLoop runs every 5 minutes and deletes filters that have not been recently used.
// Tt is started when the api is created. // Tt is started when the api is created.
func (api *PublicFilterAPI) timeoutLoop() { func (api *PublicFilterAPI) timeoutLoop() {
// TODO ek – infinite loop; add shutdown/cleanup logic
ticker := time.NewTicker(5 * time.Minute) ticker := time.NewTicker(5 * time.Minute)
for { for {
<-ticker.C <-ticker.C

@ -9,9 +9,9 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts" "github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/values"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -179,7 +179,7 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
} }
c := s.b.ChainConfig().ChainID c := s.b.ChainConfig().ChainID
if tx.ChainID().Cmp(c) != 0 { if tx.ChainID().Cmp(c) != 0 {
e := errors.Wrapf(core.ErrInvalidChainID, "current chain id:%s", c.String()) e := errors.Wrapf(values.ErrInvalidChainID, "current chain id:%s", c.String())
return common.Hash{}, e return common.Hash{}, e
} }
return SubmitStakingTransaction(ctx, s.b, tx) return SubmitStakingTransaction(ctx, s.b, tx)
@ -194,7 +194,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
} }
c := s.b.ChainConfig().ChainID c := s.b.ChainConfig().ChainID
if tx.ChainID().Cmp(c) != 0 { if tx.ChainID().Cmp(c) != 0 {
e := errors.Wrapf(core.ErrInvalidChainID, "current chain id:%s", c.String()) e := errors.Wrapf(values.ErrInvalidChainID, "current chain id:%s", c.String())
return common.Hash{}, e return common.Hash{}, e
} }
return SubmitTransaction(ctx, s.b, tx) return SubmitTransaction(ctx, s.b, tx)

@ -79,6 +79,7 @@ func (m *MemProfiling) Stop() {
// PeriodicallyScanMemSize scans memsize of the observed objects every 30 seconds. // PeriodicallyScanMemSize scans memsize of the observed objects every 30 seconds.
func (m *MemProfiling) PeriodicallyScanMemSize() { func (m *MemProfiling) PeriodicallyScanMemSize() {
go func() { go func() {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
select { select {
case <-time.After(memSizeScanTime): case <-time.After(memSizeScanTime):
@ -98,6 +99,7 @@ func (m *MemProfiling) PeriodicallyScanMemSize() {
// MaybeCallGCPeriodically runs GC manually every gcTime minutes. This is one of the options to mitigate the OOM issue. // MaybeCallGCPeriodically runs GC manually every gcTime minutes. This is one of the options to mitigate the OOM issue.
func MaybeCallGCPeriodically() { func MaybeCallGCPeriodically() {
go func() { go func() {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
select { select {
case <-time.After(gcTime): case <-time.After(gcTime):
@ -108,6 +110,7 @@ func MaybeCallGCPeriodically() {
} }
}() }()
go func() { go func() {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
select { select {
case <-time.After(memStatTime): case <-time.After(memStatTime):

@ -43,6 +43,7 @@ func (profiler *Profiler) Config(shardID uint32, metricsReportURL string) {
// LogMemory logs memory. // LogMemory logs memory.
func (profiler *Profiler) LogMemory() { func (profiler *Profiler) LogMemory() {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
// log mem usage // log mem usage
info, _ := profiler.proc.MemoryInfo() info, _ := profiler.proc.MemoryInfo()
@ -63,6 +64,7 @@ func (profiler *Profiler) LogMemory() {
// LogCPU logs CPU metrics. // LogCPU logs CPU metrics.
func (profiler *Profiler) LogCPU() { func (profiler *Profiler) LogCPU() {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
// log cpu usage // log cpu usage
percent, _ := profiler.proc.CPUPercent() percent, _ := profiler.proc.CPUPercent()

@ -0,0 +1,63 @@
// Package msgq implements a simple, finite-sized message queue. It can be used
// as a building block for a message processor pool.
package msgq
import (
"github.com/libp2p/go-libp2p-core/peer"
"github.com/pkg/errors"
)
type message struct {
content []byte
sender peer.ID
}
// MessageAdder enqueues a received message for processing. It returns without
// blocking, and may return a queue overrun error.
type MessageAdder interface {
AddMessage(content []byte, sender peer.ID) error
}
// MessageHandler is a message handler.
type MessageHandler interface {
HandleMessage(content []byte, sender peer.ID)
}
// Queue is a finite-sized message queue.
type Queue struct {
ch chan message
}
// New returns a new message queue of the given size.
func New(size int) *Queue {
return &Queue{ch: make(chan message, size)}
}
// AddMessage enqueues a received message for processing. It returns without
// blocking, and may return a queue overrun error.
func (q *Queue) AddMessage(content []byte, sender peer.ID) error {
select {
case q.ch <- message{content, sender}:
default:
return ErrRxOverrun
}
return nil
}
// HandleMessages dequeues and dispatches incoming messages using the given
// message handler, until the message queue is closed. This function can be
// spawned as a background goroutine, potentially multiple times for a pool.
func (q *Queue) HandleMessages(h MessageHandler) {
for msg := range q.ch {
h.HandleMessage(msg.content, msg.sender)
}
}
// Close closes the given queue.
func (q *Queue) Close() error {
close(q.ch)
return nil
}
// ErrRxOverrun signals that a receive queue has been overrun.
var ErrRxOverrun = errors.New("rx overrun")

@ -0,0 +1,94 @@
package msgq
import (
"fmt"
"testing"
"github.com/libp2p/go-libp2p-core/peer"
)
func TestNew(t *testing.T) {
tests := []struct {
name string
cap int
}{
{"unbuffered", 0},
{"buffered10", 10},
{"buffered100", 100},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := New(tt.cap)
if cap(got.ch) != tt.cap {
t.Errorf("New() ch cap %d, want %d", cap(got.ch), tt.cap)
}
})
}
}
func TestQueue_AddMessage(t *testing.T) {
tests := []struct {
name string
cap int
}{
{"unbuffered", 0},
{"buffered", 100},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
q := &Queue{ch: make(chan message, tt.cap)}
for i := 0; i < tt.cap+10; i++ {
var wantErr error
if i >= tt.cap {
wantErr = ErrRxOverrun
} else {
wantErr = nil
}
err := q.AddMessage([]byte{}, peer.ID(""))
if err != wantErr {
t.Fatalf("AddMessage() iter %d, error = %v, want %v",
i, err, wantErr)
}
}
})
}
}
type testMessageHandler struct {
t *testing.T
seq int
}
func (h *testMessageHandler) HandleMessage(content []byte, sender peer.ID) {
got, want := string(content), fmt.Sprint(h.seq)
if got != want {
h.t.Errorf("out-of-sequence message %v, want %v", got, want)
}
h.seq++
}
func TestQueue_HandleMessages(t *testing.T) {
ch := make(chan message, 500)
for seq := 0; seq < cap(ch); seq++ {
ch <- message{content: []byte(fmt.Sprint(seq))}
}
close(ch)
q := &Queue{ch: ch}
q.HandleMessages(&testMessageHandler{t: t})
}
func TestQueue_Close(t *testing.T) {
q := &Queue{ch: make(chan message, 100)}
err := q.Close()
if err != nil {
t.Errorf("Close() error = %v, want nil", err)
}
select {
case m, ok := <-q.ch:
if ok {
t.Errorf("unexpected message %v", m)
}
default:
t.Error("channel closed but not ready")
}
}

@ -20,6 +20,7 @@ import (
"github.com/harmony-one/harmony/contracts" "github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/values"
"github.com/harmony-one/harmony/drand" "github.com/harmony-one/harmony/drand"
"github.com/harmony-one/harmony/internal/chain" "github.com/harmony-one/harmony/internal/chain"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node" nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
@ -27,6 +28,7 @@ import (
"github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/shardchain" "github.com/harmony-one/harmony/internal/shardchain"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/msgq"
"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"
p2p_host "github.com/harmony-one/harmony/p2p/host" p2p_host "github.com/harmony-one/harmony/p2p/host"
@ -53,6 +55,18 @@ const (
TxPoolLimit = 20000 TxPoolLimit = 20000
// NumTryBroadCast is the number of times trying to broadcast // NumTryBroadCast is the number of times trying to broadcast
NumTryBroadCast = 3 NumTryBroadCast = 3
// ClientRxQueueSize is the number of client messages to queue before tail-dropping.
ClientRxQueueSize = 16384
// ShardRxQueueSize is the number of shard messages to queue before tail-dropping.
ShardRxQueueSize = 16384
// GlobalRxQueueSize is the number of global messages to queue before tail-dropping.
GlobalRxQueueSize = 16384
// ClientRxWorkers is the number of concurrent client message handlers.
ClientRxWorkers = 8
// ShardRxWorkers is the number of concurrent shard message handlers.
ShardRxWorkers = 32
// GlobalRxWorkers is the number of concurrent global message handlers.
GlobalRxWorkers = 32
) )
func (state State) String() string { func (state State) String() string {
@ -145,6 +159,11 @@ type Node struct {
// The p2p host used to send/receive p2p messages // The p2p host used to send/receive p2p messages
host p2p.Host host p2p.Host
// Incoming messages to process.
clientRxQueue *msgq.Queue
shardRxQueue *msgq.Queue
globalRxQueue *msgq.Queue
// Service manager. // Service manager.
serviceManager *service.Manager serviceManager *service.Manager
@ -372,7 +391,8 @@ func (node *Node) getTransactionsForNewBlock(
} }
selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, pendingTransactions, node.recentTxsStats, txsThrottleConfig, coinbase) selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, pendingTransactions, node.recentTxsStats, txsThrottleConfig, coinbase)
selectedStaking, unselectedStaking, invalidStaking := node.Worker.SelectStakingTransactionsForNewBlock(newBlockNum, pendingStakingTransactions, node.recentTxsStats, txsThrottleConfig, coinbase) selectedStaking, unselectedStaking, invalidStaking :=
node.Worker.SelectStakingTransactionsForNewBlock(newBlockNum, pendingStakingTransactions, coinbase)
node.pendingTransactions = make(map[common.Hash]*types.Transaction) node.pendingTransactions = make(map[common.Hash]*types.Transaction)
for _, unselectedTx := range unselected { for _, unselectedTx := range unselected {
@ -397,8 +417,30 @@ func (node *Node) getTransactionsForNewBlock(
return selected, selectedStaking return selected, selectedStaking
} }
func (node *Node) startRxPipeline(
receiver p2p.GroupReceiver, queue *msgq.Queue, numWorkers int,
) {
// consumers
for i := 0; i < numWorkers; i++ {
go queue.HandleMessages(node)
}
// provider
go node.receiveGroupMessage(receiver, queue)
}
// StartServer starts a server and process the requests by a handler. // StartServer starts a server and process the requests by a handler.
func (node *Node) StartServer() { func (node *Node) StartServer() {
// start the goroutine to receive client message
// client messages are sent by clients, like txgen, wallet
node.startRxPipeline(node.clientReceiver, node.clientRxQueue, ClientRxWorkers)
// start the goroutine to receive group message
node.startRxPipeline(node.shardGroupReceiver, node.shardRxQueue, ShardRxWorkers)
// start the goroutine to receive global message, used for cross-shard TX
// FIXME (leo): we use beacon client topic as the global topic for now
node.startRxPipeline(node.globalGroupReceiver, node.globalRxQueue, GlobalRxWorkers)
select {} select {}
} }
@ -465,14 +507,14 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), blockchain) node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), blockchain)
node.CxPool = core.NewCxPool(core.CxPoolSize) node.CxPool = core.NewCxPool(core.CxPoolSize)
node.Worker = worker.New(node.Blockchain().Config(), blockchain, chain.Engine) node.Worker = worker.New(node.Blockchain().Config(), blockchain, chain.Engine)
if node.Blockchain().ShardID() != 0 {
if node.Blockchain().ShardID() != values.BeaconChainShardID {
node.BeaconWorker = worker.New(node.Beaconchain().Config(), beaconChain, chain.Engine) node.BeaconWorker = worker.New(node.Beaconchain().Config(), beaconChain, chain.Engine)
} }
node.pendingCXReceipts = make(map[string]*types.CXReceiptsProof) node.pendingCXReceipts = make(map[string]*types.CXReceiptsProof)
node.pendingTransactions = make(map[common.Hash]*types.Transaction) node.pendingTransactions = make(map[common.Hash]*types.Transaction)
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction) node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
node.Consensus.VerifiedNewBlock = make(chan *types.Block) node.Consensus.VerifiedNewBlock = make(chan *types.Block)
// the sequence number is the next block number to be added in consensus protocol, which is always one more than current chain header block // the sequence number is the next block number to be added in consensus protocol, which is always one more than current chain header block
node.Consensus.SetBlockNum(blockchain.CurrentBlock().NumberU64() + 1) node.Consensus.SetBlockNum(blockchain.CurrentBlock().NumberU64() + 1)
@ -486,20 +528,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
} else { } else {
node.AddContractKeyAndAddress(scFaucet) node.AddContractKeyAndAddress(scFaucet)
} }
//if node.Consensus.ShardID == 0 {
// // Contracts only exist in beacon chain
// if node.isFirstTime {
// // Setup one time smart contracts
// node.CurrentStakes = make(map[common.Address]*structs.StakeInfo)
// node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked
// } else {
// node.AddContractKeyAndAddress(scStaking)
// }
//}
node.ContractCaller = contracts.NewContractCaller(node.Blockchain(), node.Blockchain().Config()) node.ContractCaller = contracts.NewContractCaller(node.Blockchain(), node.Blockchain().Config())
// Create test keys. Genesis will later need this. // Create test keys. Genesis will later need this.
var err error var err error
node.TestBankKeys, err = CreateTestBankKeys(TestAccountNumber) node.TestBankKeys, err = CreateTestBankKeys(TestAccountNumber)
@ -513,16 +542,9 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
Interface("genesis block header", node.Blockchain().GetHeaderByNumber(0)). Interface("genesis block header", node.Blockchain().GetHeaderByNumber(0)).
Msg("Genesis block hash") Msg("Genesis block hash")
// start the goroutine to receive client message node.clientRxQueue = msgq.New(ClientRxQueueSize)
// client messages are sent by clients, like txgen, wallet node.shardRxQueue = msgq.New(ShardRxQueueSize)
go node.ReceiveClientGroupMessage() node.globalRxQueue = msgq.New(GlobalRxQueueSize)
// start the goroutine to receive group message
go node.ReceiveGroupMessage()
// start the goroutine to receive global message, used for cross-shard TX
// FIXME (leo): we use beacon client topic as the global topic for now
go node.ReceiveGlobalMessage()
// Setup initial state of syncing. // Setup initial state of syncing.
node.peerRegistrationRecord = make(map[string]*syncConfig) node.peerRegistrationRecord = make(map[string]*syncConfig)

@ -69,6 +69,7 @@ func (node *Node) BroadcastCXReceiptsWithShardID(block *types.Block, commitSig [
utils.Logger().Info().Uint32("ToShardID", toShardID).Msg("[BroadcastCXReceiptsWithShardID] ReadCXReceipts and MerkleProof Found") utils.Logger().Info().Uint32("ToShardID", toShardID).Msg("[BroadcastCXReceiptsWithShardID] ReadCXReceipts and MerkleProof Found")
groupID := nodeconfig.ShardID(toShardID) groupID := nodeconfig.ShardID(toShardID)
// TODO ek – limit concurrency
go node.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(groupID)}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCXReceiptsProof(cxReceipts, merkleProof, block.Header(), commitSig, commitBitmap))) go node.host.SendMessageToGroups([]nodeconfig.GroupID{nodeconfig.NewGroupIDByShardID(groupID)}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCXReceiptsProof(cxReceipts, merkleProof, block.Header(), commitSig, commitBitmap)))
} }
@ -243,7 +244,7 @@ func (node *Node) ProcessHeaderMessage(msgPayload []byte) {
} }
func (node *Node) verifyIncomingReceipts(block *types.Block) error { func (node *Node) verifyIncomingReceipts(block *types.Block) error {
m := make(map[common.Hash]bool) m := make(map[common.Hash]struct{})
cxps := block.IncomingReceipts() cxps := block.IncomingReceipts()
for _, cxp := range cxps { for _, cxp := range cxps {
// double spent // double spent
@ -255,7 +256,7 @@ func (node *Node) verifyIncomingReceipts(block *types.Block) error {
if _, ok := m[hash]; ok { if _, ok := m[hash]; ok {
return ctxerror.New("[verifyIncomingReceipts] Double Spent!") return ctxerror.New("[verifyIncomingReceipts] Double Spent!")
} }
m[hash] = true m[hash] = struct{}{}
for _, item := range cxp.Receipts { for _, item := range cxp.Receipts {
if item.ToShardID != node.Blockchain().ShardID() { if item.ToShardID != node.Blockchain().ShardID() {

@ -14,6 +14,8 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
pb "github.com/golang/protobuf/proto" pb "github.com/golang/protobuf/proto"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
libp2p_peer "github.com/libp2p/go-libp2p-core/peer"
"github.com/harmony-one/harmony/api/proto" "github.com/harmony-one/harmony/api/proto"
proto_discovery "github.com/harmony-one/harmony/api/proto/discovery" proto_discovery "github.com/harmony-one/harmony/api/proto/discovery"
"github.com/harmony-one/harmony/api/proto/message" "github.com/harmony-one/harmony/api/proto/message"
@ -24,11 +26,11 @@ import (
nodeconfig "github.com/harmony-one/harmony/internal/configs/node" nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/msgq"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host" "github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
libp2p_peer "github.com/libp2p/go-libp2p-peer"
) )
const ( const (
@ -36,71 +38,39 @@ const (
crossLinkBatchSize = 7 crossLinkBatchSize = 7
) )
// ReceiveGlobalMessage use libp2p pubsub mechanism to receive global broadcast messages // receiveGroupMessage use libp2p pubsub mechanism to receive broadcast messages
func (node *Node) ReceiveGlobalMessage() { func (node *Node) receiveGroupMessage(
ctx := context.Background() receiver p2p.GroupReceiver, rxQueue msgq.MessageAdder,
for { ) {
if node.globalGroupReceiver == nil {
time.Sleep(100 * time.Millisecond)
continue
}
msg, sender, err := node.globalGroupReceiver.Receive(ctx)
if sender != node.host.GetID() {
//utils.Logger().Info("[PUBSUB]", "received global msg", len(msg), "sender", sender)
if err == nil {
// skip the first 5 bytes, 1 byte is p2p type, 4 bytes are message size
go node.messageHandler(msg[5:], sender)
}
}
}
}
// ReceiveGroupMessage use libp2p pubsub mechanism to receive broadcast messages
func (node *Node) ReceiveGroupMessage() {
ctx := context.Background() ctx := context.Background()
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
if node.shardGroupReceiver == nil { msg, sender, err := receiver.Receive(ctx)
time.Sleep(100 * time.Millisecond) if err != nil {
utils.Logger().Warn().Err(err).
Msg("cannot receive from group")
continue continue
} }
msg, sender, err := node.shardGroupReceiver.Receive(ctx) if sender == node.host.GetID() {
if sender != node.host.GetID() {
//utils.Logger().Info("[PUBSUB]", "received group msg", len(msg), "sender", sender)
if err == nil {
// skip the first 5 bytes, 1 byte is p2p type, 4 bytes are message size
go node.messageHandler(msg[5:], sender)
}
}
}
}
// ReceiveClientGroupMessage use libp2p pubsub mechanism to receive broadcast messages for client
func (node *Node) ReceiveClientGroupMessage() {
ctx := context.Background()
for {
if node.clientReceiver == nil {
// check less frequent on client messages
time.Sleep(100 * time.Millisecond)
continue continue
} }
msg, sender, err := node.clientReceiver.Receive(ctx) //utils.Logger().Info("[PUBSUB]", "received group msg", len(msg), "sender", sender)
if sender != node.host.GetID() { // skip the first 5 bytes, 1 byte is p2p type, 4 bytes are message size
// utils.Logger().Info("[CLIENT]", "received group msg", len(msg), "sender", sender, "error", err) if err := rxQueue.AddMessage(msg[5:], sender); err != nil {
if err == nil { utils.Logger().Warn().Err(err).
// skip the first 5 bytes, 1 byte is p2p type, 4 bytes are message size Str("sender", sender.Pretty()).
go node.messageHandler(msg[5:], sender) Msg("cannot enqueue incoming message for processing")
}
} }
} }
} }
// messageHandler parses the message and dispatch the actions // HandleMessage parses the message and dispatch the actions.
func (node *Node) messageHandler(content []byte, sender libp2p_peer.ID) { func (node *Node) HandleMessage(content []byte, sender libp2p_peer.ID) {
msgCategory, err := proto.GetMessageCategory(content) msgCategory, err := proto.GetMessageCategory(content)
if err != nil { if err != nil {
utils.Logger().Error(). utils.Logger().Error().
Err(err). Err(err).
Msg("messageHandler get message category failed") Msg("HandleMessage get message category failed")
return return
} }
@ -108,7 +78,7 @@ func (node *Node) messageHandler(content []byte, sender libp2p_peer.ID) {
if err != nil { if err != nil {
utils.Logger().Error(). utils.Logger().Error().
Err(err). Err(err).
Msg("messageHandler get message type failed") Msg("HandleMessage get message type failed")
return return
} }
@ -116,7 +86,7 @@ func (node *Node) messageHandler(content []byte, sender libp2p_peer.ID) {
if err != nil { if err != nil {
utils.Logger().Error(). utils.Logger().Error().
Err(err). Err(err).
Msg("messageHandler get message payload failed") Msg("HandleMessage get message payload failed")
return return
} }

@ -151,8 +151,7 @@ func (node *Node) proposeBeaconShardState(block *types.Block) error {
} }
nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1) nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1)
// TODO: add logic for EPoS // TODO: add logic for EPoS
shardState, err := core.CalculateNewShardState( shardState, err := core.CalculateNewShardState(node.Blockchain(), nextEpoch)
node.Blockchain(), nextEpoch, nil)
if err != nil { if err != nil {
return err return err
} }

@ -9,14 +9,11 @@ import (
"os/exec" "os/exec"
"strconv" "strconv"
"syscall" "syscall"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/contracts/structs"
"time"
proto_node "github.com/harmony-one/harmony/api/proto/node" proto_node "github.com/harmony-one/harmony/api/proto/node"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
@ -28,7 +25,7 @@ import (
) )
// validateNewShardState validate whether the new shard state root matches // validateNewShardState validate whether the new shard state root matches
func (node *Node) validateNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) error { func (node *Node) validateNewShardState(block *types.Block) error {
// Common case first – blocks without resharding proposal // Common case first – blocks without resharding proposal
header := block.Header() header := block.Header()
if header.ShardStateHash() == (common.Hash{}) { if header.ShardStateHash() == (common.Hash{}) {
@ -61,8 +58,7 @@ func (node *Node) validateNewShardState(block *types.Block, stakeInfo *map[commo
// TODO ek – this may be called from regular shards, // TODO ek – this may be called from regular shards,
// for vetting beacon chain blocks received during block syncing. // for vetting beacon chain blocks received during block syncing.
// DRand may or or may not get in the way. Test this out. // DRand may or or may not get in the way. Test this out.
expected, err := core.CalculateNewShardState( expected, err := core.CalculateNewShardState(node.Blockchain(), nextEpoch)
node.Blockchain(), nextEpoch, stakeInfo)
if err != nil { if err != nil {
return ctxerror.New("cannot calculate expected shard state"). return ctxerror.New("cannot calculate expected shard state").
WithCause(err) WithCause(err)

@ -162,6 +162,7 @@ func (p *LocalSyncingPeerProvider) SyncingPeers(shardID uint32) (peers []p2p.Pee
// DoBeaconSyncing update received beaconchain blocks and downloads missing beacon chain blocks // DoBeaconSyncing update received beaconchain blocks and downloads missing beacon chain blocks
func (node *Node) DoBeaconSyncing() { func (node *Node) DoBeaconSyncing() {
go func(node *Node) { go func(node *Node) {
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
select { select {
case beaconBlock := <-node.BeaconBlockChannel: case beaconBlock := <-node.BeaconBlockChannel:
@ -170,6 +171,7 @@ func (node *Node) DoBeaconSyncing() {
} }
}(node) }(node)
// TODO ek – infinite loop; add shutdown/cleanup logic
for { for {
if node.beaconSync == nil { if node.beaconSync == nil {
utils.Logger().Info().Msg("initializing beacon sync") utils.Logger().Info().Msg("initializing beacon sync")
@ -198,6 +200,7 @@ func (node *Node) DoBeaconSyncing() {
// DoSyncing keep the node in sync with other peers, willJoinConsensus means the node will try to join consensus after catch up // DoSyncing keep the node in sync with other peers, willJoinConsensus means the node will try to join consensus after catch up
func (node *Node) DoSyncing(bc *core.BlockChain, worker *worker.Worker, willJoinConsensus bool) { func (node *Node) DoSyncing(bc *core.BlockChain, worker *worker.Worker, willJoinConsensus bool) {
// TODO ek – infinite loop; add shutdown/cleanup logic
SyncingLoop: SyncingLoop:
for { for {
if node.stateSync == nil { if node.stateSync == nil {

@ -13,6 +13,7 @@ import (
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core"
"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/values"
"github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/core/vm"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
@ -27,11 +28,12 @@ type environment struct {
state *state.DB // apply state changes here state *state.DB // apply state changes here
gasPool *core.GasPool // available gas used to pack transactions gasPool *core.GasPool // available gas used to pack transactions
header *block.Header header *block.Header
txs []*types.Transaction txs []*types.Transaction
receipts []*types.Receipt stkingTxs staking.StakingTransactions
outcxs []*types.CXReceipt // cross shard transaction receipts (source shard) receipts []*types.Receipt
incxs []*types.CXReceiptsProof // cross shard receipts and its proof (desitinatin shard) outcxs []*types.CXReceipt // cross shard transaction receipts (source shard)
incxs []*types.CXReceiptsProof // cross shard receipts and its proof (desitinatin shard)
} }
// Worker is the main object which takes care of submitting new work to consensus engine // Worker is the main object which takes care of submitting new work to consensus engine
@ -146,12 +148,58 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
// SelectStakingTransactionsForNewBlock selects staking transactions for new block. // SelectStakingTransactionsForNewBlock selects staking transactions for new block.
func (w *Worker) SelectStakingTransactionsForNewBlock( func (w *Worker) SelectStakingTransactionsForNewBlock(
newBlockNum uint64, txs staking.StakingTransactions, newBlockNum uint64, txs staking.StakingTransactions,
recentTxsStats types.RecentTxsStats,
txsThrottleConfig *shardingconfig.TxsThrottleConfig,
coinbase common.Address) (staking.StakingTransactions, staking.StakingTransactions, staking.StakingTransactions) { coinbase common.Address) (staking.StakingTransactions, staking.StakingTransactions, staking.StakingTransactions) {
// TODO: implement staking transaction selection
t := staking.StakingTransactions{} // only beaconchain process staking transaction
return t, t, t if w.chain.ShardID() != values.BeaconChainShardID {
return nil, nil, nil
}
// staking transaction share the same gasPool with normal transactions
if w.current.gasPool == nil {
w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit())
}
selected := staking.StakingTransactions{}
unselected := staking.StakingTransactions{}
invalid := staking.StakingTransactions{}
for _, tx := range txs {
snap := w.current.state.Snapshot()
_, err := w.commitStakingTransaction(tx, coinbase)
if err != nil {
w.current.state.RevertToSnapshot(snap)
invalid = append(invalid, tx)
utils.Logger().Error().Err(err).Str("stakingTxId", tx.Hash().Hex()).Msg("Commit staking transaction error")
} else {
selected = append(selected, tx)
utils.Logger().Info().Str("stakingTxId", tx.Hash().Hex()).Uint64("txGasLimit", tx.Gas()).Msg("StakingTransaction gas limit info")
}
}
utils.Logger().Info().Uint64("newBlockNum", newBlockNum).Uint64("blockGasLimit",
w.current.header.GasLimit()).Uint64("blockGasUsed",
w.current.header.GasUsed()).Msg("[SelectStakingTransaction] Block gas limit and usage info")
return selected, unselected, invalid
}
func (w *Worker) commitStakingTransaction(tx *staking.StakingTransaction, coinbase common.Address) ([]*types.Log, error) {
snap := w.current.state.Snapshot()
gasUsed := w.current.header.GasUsed()
receipt, _, err :=
core.ApplyStakingTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &gasUsed, vm.Config{})
w.current.header.SetGasUsed(gasUsed)
if err != nil {
w.current.state.RevertToSnapshot(snap)
return nil, err
}
if receipt == nil {
return nil, fmt.Errorf("nil staking receipt")
}
w.current.stkingTxs = append(w.current.stkingTxs, tx)
w.current.receipts = append(w.current.receipts, receipt)
return receipt.Logs, nil
} }
func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
@ -348,7 +396,9 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi
s := w.current.state.Copy() s := w.current.state.Copy()
copyHeader := types.CopyHeader(w.current.header) copyHeader := types.CopyHeader(w.current.header)
block, err := w.engine.Finalize(w.chain, copyHeader, s, w.current.txs, w.current.receipts, w.current.outcxs, w.current.incxs) block, err := w.engine.Finalize(
w.chain, copyHeader, s, w.current.txs, w.current.stkingTxs, w.current.receipts, w.current.outcxs, w.current.incxs,
)
if err != nil { if err != nil {
return nil, ctxerror.New("cannot finalize block").WithCause(err) return nil, ctxerror.New("cannot finalize block").WithCause(err)
} }

@ -7,10 +7,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/bls/ffi/go/bls"
"golang.org/x/crypto/sha3"
common2 "github.com/harmony-one/harmony/internal/common" common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
"golang.org/x/crypto/sha3"
) )
var ( var (
@ -101,7 +100,7 @@ func CompareBlsPublicKey(k1, k2 BlsPublicKey) int {
return bytes.Compare(k1[:], k2[:]) return bytes.Compare(k1[:], k2[:])
} }
// NodeID represents node id (BLS address). // NodeID represents node id (BLS address)
type NodeID struct { type NodeID struct {
EcdsaAddress common.Address `json:"ecdsa_address"` EcdsaAddress common.Address `json:"ecdsa_address"`
BlsPublicKey BlsPublicKey `json:"bls_pubkey"` BlsPublicKey BlsPublicKey `json:"bls_pubkey"`

@ -2,6 +2,8 @@ package types
import ( import (
"math/big" "math/big"
"github.com/harmony-one/harmony/core/numeric"
) )
type ( type (
@ -15,14 +17,8 @@ type (
// CommissionRates defines the initial commission rates to be used for creating a // CommissionRates defines the initial commission rates to be used for creating a
// validator. // validator.
CommissionRates struct { CommissionRates struct {
Rate Dec `json:"rate" yaml:"rate"` // the commission rate charged to delegators, as a fraction Rate numeric.Dec `json:"rate" yaml:"rate"` // the commission rate charged to delegators, as a fraction
MaxRate Dec `json:"max_rate" yaml:"max_rate"` // maximum commission rate which validator can ever charge, as a fraction MaxRate numeric.Dec `json:"max_rate" yaml:"max_rate"` // maximum commission rate which validator can ever charge, as a fraction
MaxChangeRate Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum increase of the validator commission every epoch, as a fraction MaxChangeRate numeric.Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum increase of the validator commission every epoch, as a fraction
} }
) )
// NewCommission returns a new commission object
func NewCommission(rate Dec, maxRate Dec, maxChangeRate Dec, height *big.Int) Commission {
commissionRates := CommissionRates{Rate: rate, MaxRate: maxRate, MaxChangeRate: maxChangeRate}
return Commission{CommissionRates: commissionRates, UpdateHeight: height}
}

@ -3,6 +3,7 @@ package types
import ( import (
"math/big" "math/big"
"github.com/harmony-one/harmony/core/numeric"
"github.com/harmony-one/harmony/internal/common" "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/shard"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -38,7 +39,7 @@ func (d Directive) String() string {
// NewValidator - type for creating a new validator // NewValidator - type for creating a new validator
type NewValidator struct { type NewValidator struct {
Description `json:"ties" yaml:"ties"` Description `json:"description" yaml:"description"`
CommissionRates `json:"commission" yaml:"commission"` CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"` StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
@ -50,7 +51,7 @@ type NewValidator struct {
type EditValidator struct { type EditValidator struct {
Description Description
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"` StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
CommissionRate Dec `json:"commission_rate" yaml:"commission_rate"` CommissionRate numeric.Dec `json:"commission_rate" yaml:"commission_rate"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
} }

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/values"
"github.com/harmony-one/harmony/crypto/hash" "github.com/harmony-one/harmony/crypto/hash"
) )
@ -111,7 +111,7 @@ var big8 = big.NewInt(8)
// Sender returns the sender address of the given signer. // Sender returns the sender address of the given signer.
func (s EIP155Signer) Sender(tx *StakingTransaction) (common.Address, error) { func (s EIP155Signer) Sender(tx *StakingTransaction) (common.Address, error) {
if tx.ChainID().Cmp(s.chainID) != 0 { if tx.ChainID().Cmp(s.chainID) != 0 {
return common.Address{}, core.ErrInvalidChainID return common.Address{}, values.ErrInvalidChainID
} }
V := new(big.Int).Sub(tx.data.V, s.chainIDMul) V := new(big.Int).Sub(tx.data.V, s.chainIDMul)
V.Sub(V, big8) V.Sub(V, big8)

@ -86,6 +86,11 @@ func (tx *StakingTransaction) WithSignature(signer Signer, sig []byte) (*Staking
return cpy, nil return cpy, nil
} }
// Gas returns gas of StakingTransaction.
func (tx *StakingTransaction) Gas() uint64 {
return tx.data.GasLimit
}
// ChainID is what chain this staking transaction for // ChainID is what chain this staking transaction for
func (tx *StakingTransaction) ChainID() *big.Int { func (tx *StakingTransaction) ChainID() *big.Int {
return deriveChainID(tx.data.V) return deriveChainID(tx.data.V)

@ -18,14 +18,22 @@ const (
// Validator - data fields for a validator // Validator - data fields for a validator
type Validator struct { type Validator struct {
Address common.Address `json:"address" yaml:"address"` // ECDSA address of the validator // ECDSA address of the validator
ValidatingPubKey bls.PublicKey `json:"validating_pub_key" yaml:"validating_pub_key"` // The BLS public key of the validator for consensus Address common.Address `json:"address" yaml:"address"`
Description Description `json:"description" yaml:"description"` // description for the validator // The BLS public key of the validator for consensus
Active bool `json:"active" yaml:"active"` // Is the validator active in the validating process or not ValidatingPubKey bls.PublicKey `json:"validating_pub_key" yaml:"validating_pub_key"`
Stake *big.Int `json:"stake" yaml:"stake"` // The stake put by the validator itself // The stake put by the validator itself
UnbondingHeight *big.Int `json:"unbonding_height" yaml:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding Stake *big.Int `json:"stake" yaml:"stake"`
Commission Commission `json:"commission" yaml:"commission"` // commission parameters // if unbonding, height at which this validator has begun unbonding
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"` // validator's self declared minimum self delegation UnbondingHeight *big.Int `json:"unbonding_height" yaml:"unbonding_height"`
// validator's self declared minimum self delegation
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
// commission parameters
Commission `json:"commission" yaml:"commission"`
// description for the validator
Description `json:"description" yaml:"description"`
// Is the validator active in the validating process or not
Active bool `json:"active" yaml:"active"`
} }
// Description - some possible IRL connections // Description - some possible IRL connections

Loading…
Cancel
Save