Further progress on staking (#1709)

* [staking] Factor some project errors into values core/pkg. Thread stking Txs through Finalize

* [staking] Incorporate Chao code from PR 1700

* [staking] Remove dead staking code, create const values, factor out dec from staking

* [staking] Remove voting power for now till discussion, factor out more error values
pull/1713/head
Edgar Aroutiounian 5 years ago committed by GitHub
parent 3b52046a39
commit 97efce2766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/client/txgen/main.go
  2. 44
      cmd/staking/root.go
  3. 35
      consensus/README.md
  4. 113
      consensus/consensus.go
  5. 12
      consensus/engine/consensus_engine.go
  6. 35
      contracts/structs/structs.go
  7. 6
      core/block_validator.go
  8. 16
      core/blockchain.go
  9. 10
      core/chain_makers.go
  10. 4
      core/gaspool.go
  11. 2
      core/numeric/decimal.go
  12. 2
      core/numeric/decimal_test.go
  13. 39
      core/resharding.go
  14. 16
      core/state_processor.go
  15. 8
      core/state_transition.go
  16. 65
      core/tx_pool.go
  17. 22
      core/tx_pool_test.go
  18. 24
      core/types/block.go
  19. 10
      core/values/blockchain.go
  20. 38
      core/values/error.go
  21. 12
      internal/chain/engine.go
  22. 2
      internal/chain/reward.go
  23. 6
      internal/hmyapi/transactionpool.go
  24. 21
      node/node.go
  25. 3
      node/node_newblock.go
  26. 10
      node/node_resharding.go
  27. 72
      node/worker/worker.go
  28. 5
      shard/shard_state.go
  29. 14
      staking/types/commission.go
  30. 5
      staking/types/messages.go
  31. 4
      staking/types/sign.go
  32. 5
      staking/types/transaction.go
  33. 24
      staking/types/validator.go

@ -88,7 +88,6 @@ func setUpTXGen() *node.Node {
shardID := *shardIDFlag
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
myhost, err := p2pimpl.NewHost(&selfPeer, nodePriKey)
@ -103,7 +102,6 @@ func setUpTXGen() *node.Node {
chainDBFactory := &shardchain.MemDBFactory{}
txGen := node.New(myhost, consensusObj, chainDBFactory, false) //Changed it : no longer archival node.
txGen.Client = client.NewClient(txGen.GetHost(), uint32(shardID))
consensusObj.SetStakeInfoFinder(gsif)
consensusObj.ChainReader = txGen.Blockchain()
consensusObj.PublicKeys = nil
genesisShardingConfig := core.ShardingSchedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch))

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

@ -1,12 +1,17 @@
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
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
To reach the consensus of the next block, there are 3 phases: announce(i.e. pre-prepare in PBFT), prepare and commit.
To reach the consensus of the next block, there are 3 phases: announce(i.e. pre-prepare in PBFT), prepare and commit.
* Announce(leader): The leader broadcasts ANNOUNCE message along with candidate of the next block.
* Prepare(validator): The validator will validate the block sent by leader and send PREPARE message; if the block is invalid, the validator will propose view change. If the prepare timeout, the validator will also propose view change.
@ -42,8 +47,8 @@ type PbftLog struct {
messages []*PbftMessage
}
// entry point and main loop;
// in each loop, the node will receive PBFT message from peers with timeout,
// entry point and main loop;
// in each loop, the node will receive PBFT message from peers with timeout,
// then update its state accordingly. handleMessageUpdate function handles various kinds of messages and update its state
// it will also send new PBFT message (if not null) to its peers.
// in the same loop, the node will also check whether it should send view changing message to new leader
@ -75,27 +80,9 @@ func (consensus *Consensus) Start(stopChan chan struct{}, stoppedChan chan struc
case <-stopChan:
return
}
}
}
}
```

@ -8,19 +8,13 @@ import (
"time"
"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/harmony/contracts/structs"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
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/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/shard"
)
const (
@ -150,9 +144,6 @@ type Consensus struct {
// MessageSender takes are of sending consensus message and the corresponding retry logic.
msgSender *MessageSender
// Staking information finder
stakeInfoFinder StakeInfoFinder
// Used to convey to the consensus main loop that block syncing has finished.
syncReadyChan chan struct{}
// 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
}
// 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
// changes when it should, e.g. leader timeout.
//
@ -235,19 +214,6 @@ func (consensus *Consensus) GetBlockReward() *big.Int {
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
// TODO: put shardId into chain reader's chain config
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.msgSender = NewMessageSender(host)
consensus.blockNumLowChan = make(chan struct{})
// pbft related
consensus.PbftLog = NewPbftLog()
consensus.phase = Announce
consensus.mode = PbftMode{mode: Normal}
// pbft timeout
consensus.consensusTimeout = createTimeout()
consensus.prepareSigs = map[string]*bls.Sign{}
consensus.commitSigs = map[string]*bls.Sign{}
consensus.CommitteePublicKeys = make(map[string]bool)
consensus.validators.Store(leader.ConsensusPubKey.SerializeToHexStr(), leader)
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
consensus.viewID = 0
consensus.ShardID = ShardID
consensus.MsgChan = make(chan []byte)
consensus.syncReadyChan = make(chan struct{})
consensus.syncNotReadyChan = make(chan struct{})
consensus.commitFinishChan = make(chan uint64)
consensus.ReadySignal = make(chan struct{})
consensus.lastBlockReward = big.NewInt(0)
// channel for receiving newly generated VDF
consensus.RndChannel = make(chan [vdfAndSeedSize]byte)
consensus.uniqueIDInstance = utils.GetUniqueValidatorIDInstance()
memprofiling.GetMemProfiling().Add("consensus.pbftLog", consensus.PbftLog)
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
}

@ -4,12 +4,12 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
"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
@ -77,8 +77,12 @@ type Engine interface {
// and assembles the final block.
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt, incxs []*types.CXReceiptsProof) (*types.Block, error)
Finalize(
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
// 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/crypto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/internal/ctxerror"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state"
"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"
)
@ -58,7 +58,7 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Check whether the block's known, and if not, that it's linkable
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.HasBlock(block.ParentHash(), block.NumberU64()-1) {

@ -35,19 +35,18 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp"
"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"
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/state"
"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/internal/ctxerror"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
lru "github.com/hashicorp/golang-lru"
)
var (
@ -1250,7 +1249,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
err = bc.Validator().ValidateBody(block)
}
switch {
case err == ErrKnownBlock:
case err == values.ErrKnownBlock:
// 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.
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,
// creating one if needed.
func (bc *BlockChain) GetShardState(
epoch *big.Int,
stakeInfo *map[common.Address]*structs.StakeInfo,
) (shard.State, error) {
func (bc *BlockChain) GetShardState(epoch *big.Int) (shard.State, error) {
shardState, err := bc.ReadShardState(epoch)
if err == nil { // TODO ek – distinguish ErrNotFound
return shardState, err
}
shardState, err = CalculateNewShardState(bc, epoch, stakeInfo)
shardState, err = CalculateNewShardState(bc, epoch)
if err != nil {
return nil, err
}

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

@ -19,6 +19,8 @@ package core
import (
"fmt"
"math"
"github.com/harmony-one/harmony/core/values"
)
// 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.
func (gp *GasPool) SubGas(amount uint64) error {
if uint64(*gp) < amount {
return ErrGasLimitReached
return values.ErrGasLimitReached
}
*(*uint64)(gp) -= amount
return nil

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

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

@ -9,8 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/contracts/structs"
common2 "github.com/harmony-one/harmony/internal/common"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"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
func CalculateNewShardState(
bc *BlockChain, epoch *big.Int,
stakeInfo *map[common.Address]*structs.StakeInfo,
) (shard.State, error) {
func CalculateNewShardState(bc *BlockChain, epoch *big.Int) (shard.State, error) {
if epoch.Cmp(big.NewInt(GenesisEpoch)) == 0 {
return CalculateInitShardState(), nil
}
@ -171,42 +166,10 @@ func CalculateNewShardState(
return nil, ctxerror.New("cannot retrieve previous sharding state").
WithCause(err)
}
newNodeList := ss.UpdateShardingState(stakeInfo)
utils.Logger().Info().Float64("percentage", CuckooRate).Msg("Cuckoo Rate")
ss.Reshard(newNodeList, CuckooRate)
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
// configuration. We are OK for the time being,
// 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/crypto"
"github.com/harmony-one/harmony/block"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"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/params"
"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
@ -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)
_, 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 {
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
}
// 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
func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *block.Header, cxp *types.CXReceiptsProof) error {
if cxp == nil {

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

@ -18,7 +18,6 @@ package core
import (
"context"
"errors"
"fmt"
"math"
"math/big"
@ -30,11 +29,11 @@ import (
"github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/metrics"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/state"
"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"
)
@ -43,44 +42,6 @@ const (
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 (
evictionInterval = time.Minute // Time interval to check for evictable transactions
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 {
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
return ErrOversizedData
return values.ErrOversizedData
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 {
return ErrNegativeValue
return values.ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit
return values.ErrGasLimit
}
// Make sure the transaction is signed properly
from, err := types.Sender(pool.signer, tx)
if err != nil {
return ErrInvalidSender
return values.ErrInvalidSender
}
// 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
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
return ErrUnderpriced
return values.ErrUnderpriced
}
// Ensure the transaction adheres to nonce ordering
if pool.currentState.GetNonce(from) > tx.Nonce() {
return ErrNonceTooLow
return values.ErrNonceTooLow
}
// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
return ErrInsufficientFunds
return values.ErrInsufficientFunds
}
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return ErrIntrinsicGas
return values.ErrIntrinsicGas
}
return nil
}
@ -673,7 +634,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
Str("price", tx.GasPrice().String()).
Msg("Discarding underpriced transaction")
underpricedTxCounter.Inc(1)
return false, ErrUnderpriced
return false, values.ErrUnderpriced
}
// 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)
@ -693,7 +654,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
inserted, old := list.Add(tx, pool.config.PriceBump)
if !inserted {
pendingDiscardCounter.Inc(1)
return false, ErrReplaceUnderpriced
return false, values.ErrReplaceUnderpriced
}
// New transaction is better, replace old one
if old != nil {
@ -759,7 +720,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er
if !inserted {
// An older transaction was better, discard this
queuedDiscardCounter.Inc(1)
return false, ErrReplaceUnderpriced
return false, values.ErrReplaceUnderpriced
}
// Discard any previous transaction and mark this
if old != nil {

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

@ -30,10 +30,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"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"
blockfactory "github.com/harmony-one/harmony/block/factory"
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/internal/utils"
"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.
@ -181,12 +181,13 @@ func init() {
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 {
header *block.Header
uncles []*block.Header
transactions Transactions
incomingReceipts CXReceiptsProofs
header *block.Header
uncles []*block.Header
transactions Transactions
stakingTransactions staking.StakingTransactions
incomingReceipts CXReceiptsProofs
// caches
hash atomic.Value
@ -347,6 +348,11 @@ func (b *Block) Transactions() Transactions {
return b.transactions
}
// StakingTransactions returns stakingTransactions.
func (b *Block) StakingTransactions() staking.StakingTransactions {
return b.stakingTransactions
}
// IncomingReceipts returns verified outgoing receipts
func (b *Block) IncomingReceipts() CXReceiptsProofs {
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
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
package values
import (
"github.com/pkg/errors"
@ -31,6 +31,10 @@ var (
// ErrBlacklistedHash is returned if a block to import is on the blacklist.
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
// next one expected based on the local chain.
ErrNonceTooHigh = errors.New("nonce too high")
@ -40,4 +44,36 @@ var (
// ErrInvalidChainID when ChainID of signer does not match that of running node
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")
)

@ -6,9 +6,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"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/consensus/engine"
"github.com/harmony-one/harmony/core"
@ -17,6 +14,9 @@ import (
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
"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{}
@ -149,7 +149,11 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header)
// Finalize implements Engine, accumulating the block rewards,
// 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
// Header seems complete, assemble into a block and return
if err := AccumulateRewards(chain, state, header); err != nil {

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

@ -9,9 +9,9 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"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/types"
"github.com/harmony-one/harmony/core/values"
internal_common "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
@ -179,7 +179,7 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
}
c := s.b.ChainConfig().ChainID
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 SubmitStakingTransaction(ctx, s.b, tx)
@ -194,7 +194,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
}
c := s.b.ChainConfig().ChainID
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 SubmitTransaction(ctx, s.b, tx)

@ -20,6 +20,7 @@ import (
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core"
"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/internal/chain"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
@ -372,7 +373,8 @@ func (node *Node) getTransactionsForNewBlock(
}
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)
for _, unselectedTx := range unselected {
@ -465,14 +467,14 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, node.Blockchain().Config(), blockchain)
node.CxPool = core.NewCxPool(core.CxPoolSize)
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.pendingCXReceipts = make(map[string]*types.CXReceiptsProof)
node.pendingTransactions = make(map[common.Hash]*types.Transaction)
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
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
node.Consensus.SetBlockNum(blockchain.CurrentBlock().NumberU64() + 1)
@ -486,20 +488,7 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc
} else {
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())
// Create test keys. Genesis will later need this.
var err error
node.TestBankKeys, err = CreateTestBankKeys(TestAccountNumber)

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

@ -9,14 +9,11 @@ import (
"os/exec"
"strconv"
"syscall"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"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"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
@ -28,7 +25,7 @@ import (
)
// 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
header := block.Header()
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,
// for vetting beacon chain blocks received during block syncing.
// DRand may or or may not get in the way. Test this out.
expected, err := core.CalculateNewShardState(
node.Blockchain(), nextEpoch, stakeInfo)
expected, err := core.CalculateNewShardState(node.Blockchain(), nextEpoch)
if err != nil {
return ctxerror.New("cannot calculate expected shard state").
WithCause(err)

@ -13,6 +13,7 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/values"
"github.com/harmony-one/harmony/core/vm"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/ctxerror"
@ -27,11 +28,12 @@ type environment struct {
state *state.DB // apply state changes here
gasPool *core.GasPool // available gas used to pack transactions
header *block.Header
txs []*types.Transaction
receipts []*types.Receipt
outcxs []*types.CXReceipt // cross shard transaction receipts (source shard)
incxs []*types.CXReceiptsProof // cross shard receipts and its proof (desitinatin shard)
header *block.Header
txs []*types.Transaction
stkingTxs staking.StakingTransactions
receipts []*types.Receipt
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
@ -146,12 +148,58 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
// SelectStakingTransactionsForNewBlock selects staking transactions for new block.
func (w *Worker) SelectStakingTransactionsForNewBlock(
newBlockNum uint64, txs staking.StakingTransactions,
recentTxsStats types.RecentTxsStats,
txsThrottleConfig *shardingconfig.TxsThrottleConfig,
coinbase common.Address) (staking.StakingTransactions, staking.StakingTransactions, staking.StakingTransactions) {
// TODO: implement staking transaction selection
t := staking.StakingTransactions{}
return t, t, t
// only beaconchain process staking transaction
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) {
@ -348,7 +396,9 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi
s := w.current.state.Copy()
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 {
return nil, ctxerror.New("cannot finalize block").WithCause(err)
}

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

@ -2,6 +2,8 @@ package types
import (
"math/big"
"github.com/harmony-one/harmony/core/numeric"
)
type (
@ -15,14 +17,8 @@ type (
// CommissionRates defines the initial commission rates to be used for creating a
// validator.
CommissionRates struct {
Rate 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
MaxChangeRate Dec `json:"max_change_rate" yaml:"max_change_rate"` // maximum increase of the validator commission every epoch, as a fraction
Rate numeric.Dec `json:"rate" yaml:"rate"` // the commission rate charged to delegators, as a fraction
MaxRate numeric.Dec `json:"max_rate" yaml:"max_rate"` // maximum commission rate which validator can ever charge, 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 (
"math/big"
"github.com/harmony-one/harmony/core/numeric"
"github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/shard"
"github.com/pkg/errors"
@ -38,7 +39,7 @@ func (d Directive) String() string {
// NewValidator - type for creating a new validator
type NewValidator struct {
Description `json:"ties" yaml:"ties"`
Description `json:"description" yaml:"description"`
CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
StakingAddress common.Address `json:"staking_address" yaml:"staking_address"`
@ -50,7 +51,7 @@ type NewValidator struct {
type EditValidator struct {
Description
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"`
}

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"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"
)
@ -111,7 +111,7 @@ var big8 = big.NewInt(8)
// Sender returns the sender address of the given signer.
func (s EIP155Signer) Sender(tx *StakingTransaction) (common.Address, error) {
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.Sub(V, big8)

@ -86,6 +86,11 @@ func (tx *StakingTransaction) WithSignature(signer Signer, sig []byte) (*Staking
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
func (tx *StakingTransaction) ChainID() *big.Int {
return deriveChainID(tx.data.V)

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

Loading…
Cancel
Save