Merge branch 'master' of github.com:harmony-one/harmony into remove_quorum

pull/1779/head
Dennis Won 5 years ago
commit 656bbc63f6
  1. 3
      api/service/syncing/syncing.go
  2. 4
      cmd/client/wallet/main.go
  3. 58
      cmd/staking/root.go
  4. 4
      consensus/engine/consensus_engine.go
  5. 183
      core/blockchain.go
  6. 27
      core/core_test.go
  7. 22
      core/rawdb/accessors_chain.go
  8. 9
      core/state/state_object.go
  9. 45
      core/state/statedb.go
  10. 67
      core/state_processor.go
  11. 112
      core/state_transition.go
  12. 41
      core/types/transaction.go
  13. 7
      core/vm/interface.go
  14. 33
      hmy/api_backend.go
  15. 2
      hmy/backend.go
  16. 2
      internal/configs/sharding/localnet.go
  17. 2
      internal/configs/sharding/mainnet.go
  18. 51
      internal/configs/sharding/testnet.go
  19. 11
      internal/hmyapi/backend.go
  20. 255
      internal/hmyapi/blockchain.go
  21. 18
      internal/hmyapi/transactionpool.go
  22. 11
      internal/hmyapi/types.go
  23. 6
      internal/params/config.go
  24. 26
      node/node.go
  25. 18
      node/node_explorer.go
  26. 2
      node/node_handler.go
  27. 8
      node/node_handler_test.go
  28. 4
      node/node_newblock.go
  29. 148
      node/worker/worker.go
  30. 2
      node/worker/worker_test.go
  31. 18
      staking/params.go
  32. 251
      staking/types/delegation.go
  33. 8
      staking/types/messages.go
  34. 61
      staking/types/transaction.go
  35. 54
      staking/types/validator.go
  36. 4
      staking/types/validator_test.go
  37. 18
      test/chain/main.go

@ -531,7 +531,6 @@ func (ss *StateSync) updateBlockAndStatus(block *types.Block, bc *core.BlockChai
utils.Logger().Info().Str("blockHex", bc.CurrentBlock().Hash().Hex()).Msg("[SYNC] Current Block")
// Verify block signatures
// TODO chao: only when block is verified against last commit sigs, we can update the block and status
if block.NumberU64() > 1 {
// Verify signature every 100 blocks
verifySig := block.NumberU64()%100 == 0
@ -546,7 +545,7 @@ func (ss *StateSync) updateBlockAndStatus(block *types.Block, bc *core.BlockChai
}
}
_, err := bc.InsertChain([]*types.Block{block})
_, err := bc.InsertChain([]*types.Block{block}, false /* verifyHeaders */)
if err != nil {
utils.Logger().Error().Err(err).Msgf("[SYNC] Error adding new block to blockchain %d %d", block.NumberU64(), block.ShardID())

@ -94,7 +94,7 @@ var (
transferSenderPtr = transferCommand.String("from", "0", "Specify the sender account address or index")
transferReceiverPtr = transferCommand.String("to", "", "Specify the receiver account")
transferAmountPtr = transferCommand.Float64("amount", 0, "Specify the amount to transfer")
transferGasPricePtr = transferCommand.Uint64("gasPrice", 0, "Specify the gas price amount. Unit is Nano.")
transferGasPricePtr = transferCommand.Uint64("gasPrice", 1, "Specify the gas price amount. Unit is Nano.")
transferShardIDPtr = transferCommand.Int("shardID", -1, "Specify the shard ID for the transfer")
transferToShardIDPtr = transferCommand.Int("toShardID", -1, "Specify the destination shard ID for the transfer")
transferInputDataPtr = transferCommand.String("inputData", "", "Base64-encoded input data to embed in the transaction")
@ -976,6 +976,8 @@ func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uin
return err
}
fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex())
json, err := tx.MarshalJSON()
fmt.Printf("Transaction Submitted for shard %d: %s\n", int(shardID), string(json))
// FIXME (leo): how to we know the tx was successful sent to the network
// this is a hacky way to wait for sometime
time.Sleep(3 * time.Second)

@ -18,6 +18,7 @@ import (
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/accounts/keystore"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/spf13/cobra"
@ -58,29 +59,30 @@ func (s *staker) run(cmd *cobra.Command, args []string) error {
p.DeserializeHexStr(testBLSPubKey)
pub := shard.BlsPublicKey{}
pub.FromLibBLSPublicKey(p)
// return staking.DirectiveCreateValidator, staking.CreateValidator{
// 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),
return staking.DirectiveCreateValidator, staking.CreateValidator{
Description: &staking.Description{
Name: "SuperHero",
Identity: "YouWouldNotKnow",
Website: "Secret Website",
SecurityContact: "Mr.DoubleZeroSeven",
Details: "blah blah blah",
},
CommissionRates: staking.CommissionRates{
Rate: numeric.NewDec(100),
MaxRate: numeric.NewDec(150),
MaxChangeRate: numeric.NewDec(5),
},
MinSelfDelegation: big.NewInt(10),
MaxTotalDelegation: big.NewInt(3000),
ValidatorAddress: common.Address(dAddr),
SlotPubKeys: []shard.BlsPublicKey{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)
@ -99,8 +101,16 @@ func (s *staker) run(cmd *cobra.Command, args []string) error {
if err := rlp.DecodeBytes(enc, tx); err != nil {
return err
}
fmt.Printf("In Client side: %+v\n", tx)
// return nil
payload, err := tx.RLPEncodeStakeMsg()
restored, errRestor := staking.RLPDecodeStakeMsg(
payload, staking.DirectiveCreateValidator,
)
fmt.Printf("In Client side: %+v\n", restored)
fmt.Println(errRestor)
rlp.DecodeBytes(enc, tx)
hexSignature := hexutil.Encode(enc)
param := []interface{}{hexSignature}

@ -77,9 +77,7 @@ 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,
Finalize(chain ChainReader, header *block.Header, state *state.DB, txs []*types.Transaction,
receipts []*types.Receipt, outcxs []*types.CXReceipt,
incxs []*types.CXReceiptsProof, stks []*staking.StakingTransaction) (*types.Block, error)

@ -57,19 +57,19 @@ var (
)
const (
bodyCacheLimit = 256
blockCacheLimit = 256
receiptsCacheLimit = 32
maxFutureBlocks = 256
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 2
commitsCacheLimit = 10
epochCacheLimit = 10
randomnessCacheLimit = 10
stakingCacheLimit = 256
validatorListCacheLimit = 2
bodyCacheLimit = 256
blockCacheLimit = 256
receiptsCacheLimit = 32
maxFutureBlocks = 256
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 2
commitsCacheLimit = 10
epochCacheLimit = 10
randomnessCacheLimit = 10
stakingCacheLimit = 256
validatorMapCacheLimit = 2
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -122,18 +122,18 @@ type BlockChain struct {
currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
receiptsCache *lru.Cache // Cache for the most recent receipts per block
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
shardStateCache *lru.Cache
lastCommitsCache *lru.Cache
epochCache *lru.Cache // Cache epoch number → first block number
randomnessCache *lru.Cache // Cache for vrf/vdf
stakingCache *lru.Cache // Cache for staking validator
validatorListCache *lru.Cache // Cache of validator list
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
receiptsCache *lru.Cache // Cache for the most recent receipts per block
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
shardStateCache *lru.Cache
lastCommitsCache *lru.Cache
epochCache *lru.Cache // Cache epoch number → first block number
randomnessCache *lru.Cache // Cache for vrf/vdf
stakingCache *lru.Cache // Cache for staking validator
validatorMapCache *lru.Cache // Cache of validator list
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
@ -171,30 +171,30 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
epochCache, _ := lru.New(epochCacheLimit)
randomnessCache, _ := lru.New(randomnessCacheLimit)
stakingCache, _ := lru.New(stakingCacheLimit)
validatorListCache, _ := lru.New(validatorListCacheLimit)
validatorMapCache, _ := lru.New(validatorMapCacheLimit)
bc := &BlockChain{
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
shouldPreserve: shouldPreserve,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
shardStateCache: shardCache,
lastCommitsCache: commitsCache,
epochCache: epochCache,
randomnessCache: randomnessCache,
stakingCache: stakingCache,
validatorListCache: validatorListCache,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
shouldPreserve: shouldPreserve,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
shardStateCache: shardCache,
lastCommitsCache: commitsCache,
epochCache: epochCache,
randomnessCache: randomnessCache,
stakingCache: stakingCache,
validatorMapCache: validatorMapCache,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
}
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@ -814,7 +814,7 @@ func (bc *BlockChain) procFutureBlocks() {
// Insert one by one as chain insertion needs contiguous ancestry between blocks
for i := range blocks {
bc.InsertChain(blocks[i : i+1])
bc.InsertChain(blocks[i:i+1], true /* verifyHeaders */)
}
}
}
@ -1140,8 +1140,8 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
// wrong.
//
// After insertion is done, all accumulated events will be fired.
func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
n, events, logs, err := bc.insertChain(chain)
func (bc *BlockChain) InsertChain(chain types.Blocks, verifyHeaders bool) (int, error) {
n, events, logs, err := bc.insertChain(chain, verifyHeaders)
bc.PostChainEvents(events, logs)
if err == nil {
for idx, block := range chain {
@ -1190,7 +1190,7 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// insertChain will execute the actual chain insertion and event aggregation. The
// only reason this method exists as a separate one is to make locking cleaner
// with deferred statements.
func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*types.Log, error) {
func (bc *BlockChain) insertChain(chain types.Blocks, verifyHeaders bool) (int, []interface{}, []*types.Log, error) {
// Sanity check that we have something meaningful to import
if len(chain) == 0 {
return 0, nil, nil, nil
@ -1205,7 +1205,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
Str("parent", chain[i].ParentHash().Hex()).
Str("prevnumber", chain[i-1].Number().String()).
Str("prevhash", chain[i-1].Hash().Hex()).
Msg("Non contiguous block insert")
Msg("insertChain: non contiguous block insert")
return 0, nil, nil, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].NumberU64(),
chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4])
@ -1227,16 +1227,23 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
lastCanon *types.Block
coalescedLogs []*types.Log
)
// Start the parallel header verifier
headers := make([]*block.Header, len(chain))
seals := make([]bool, len(chain))
for i, block := range chain {
headers[i] = block.Header()
seals[i] = true
var verifyHeadersResults <-chan error
// If the block header chain has not been verified, conduct header verification here.
if verifyHeaders {
headers := make([]*block.Header, len(chain))
seals := make([]bool, len(chain))
for i, block := range chain {
headers[i] = block.Header()
seals[i] = true
}
// Note that VerifyHeaders verifies headers in the chain in parallel
abort, results := bc.Engine().VerifyHeaders(bc, headers, seals)
verifyHeadersResults = results
defer close(abort)
}
abort, results := bc.Engine().VerifyHeaders(bc, headers, seals)
defer close(abort)
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
//senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)
@ -1251,7 +1258,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
// Wait for the block's verification to complete
bstart := time.Now()
err := <-results
var err error
if verifyHeaders {
err = <-verifyHeadersResults
}
if err == nil {
err = bc.Validator().ValidateBody(block)
}
@ -1308,7 +1318,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
if len(winner) > 0 {
// Import all the pruned blocks to make the state available
bc.chainmu.Unlock()
_, evs, logs, err := bc.insertChain(winner)
_, evs, logs, err := bc.insertChain(winner, true /* verifyHeaders */)
bc.chainmu.Lock()
events, coalescedLogs = evs, logs
@ -2280,23 +2290,22 @@ func (bc *BlockChain) WriteStakingValidator(v *staking.ValidatorWrapper) error {
return nil
}
// ReadValidatorList reads the addresses of current all validators
func (bc *BlockChain) ReadValidatorList() ([]common.Address, error) {
if cached, ok := bc.validatorListCache.Get("validatorList"); ok {
// ReadValidatorMap reads the addresses of current all validators
func (bc *BlockChain) ReadValidatorMap() (map[common.Address]struct{}, error) {
if cached, ok := bc.validatorMapCache.Get("validatorMap"); ok {
by := cached.([]byte)
list := []common.Address{}
if err := rlp.DecodeBytes(by, &list); err != nil {
m := make(map[common.Address]struct{})
if err := rlp.DecodeBytes(by, &m); err != nil {
return nil, err
}
return list, nil
return m, nil
}
return rawdb.ReadValidatorList(bc.db)
return rawdb.ReadValidatorMap(bc.db)
}
// WriteValidatorList writes the list of validator addresses to database
func (bc *BlockChain) WriteValidatorList(addrs []common.Address) error {
err := rawdb.WriteValidatorList(bc.db, addrs)
// WriteValidatorMap writes the list of validator addresses to database
func (bc *BlockChain) WriteValidatorMap(addrs map[common.Address]struct{}) error {
err := rawdb.WriteValidatorMap(bc.db, addrs)
if err != nil {
return err
}
@ -2304,7 +2313,33 @@ func (bc *BlockChain) WriteValidatorList(addrs []common.Address) error {
if err != nil {
return err
}
bc.validatorListCache.Add("validatorList", by)
bc.validatorMapCache.Add("validatorMap", by)
return nil
}
// UpdateValidatorMap updates the validator map according to staking transaction
func (bc *BlockChain) UpdateValidatorMap(tx *staking.StakingTransaction) error {
switch tx.StakingType() {
case staking.DirectiveCreateValidator:
createValidator := tx.StakingMessage().(staking.CreateValidator)
m, err := bc.ReadValidatorMap()
if err != nil {
return err
}
if m == nil {
m = make(map[common.Address]struct{})
}
m[createValidator.ValidatorAddress] = struct{}{}
err = bc.WriteValidatorMap(m)
return err
// following cases are placeholder for now
case staking.DirectiveEditValidator:
case staking.DirectiveDelegate:
case staking.DirectiveUndelegate:
case staking.DirectiveCollectRewards:
default:
}
return nil
}

@ -10,13 +10,12 @@ import (
)
func TestIsEpochBlock(t *testing.T) {
block1 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(10)).Header(), nil, nil, nil, nil, nil)
block2 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(0)).Header(), nil, nil, nil, nil, nil)
block3 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(344064)).Header(), nil, nil, nil, nil, nil)
block4 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(77)).Header(), nil, nil, nil, nil, nil)
block5 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(78)).Header(), nil, nil, nil, nil, nil)
block6 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(188)).Header(), nil, nil, nil, nil, nil)
block7 := types.NewBlock(blockfactory.NewTestHeader().With().Number(big.NewInt(189)).Header(), nil, nil, nil, nil, nil)
blockNumbered := func(n int64) *types.Block {
return types.NewBlock(
blockfactory.NewTestHeader().With().Number(big.NewInt(n)).Header(),
nil, nil, nil, nil, nil,
)
}
tests := []struct {
schedule shardingconfig.Schedule
block *types.Block
@ -24,37 +23,37 @@ func TestIsEpochBlock(t *testing.T) {
}{
{
shardingconfig.MainnetSchedule,
block1,
blockNumbered(10),
false,
},
{
shardingconfig.MainnetSchedule,
block2,
blockNumbered(0),
true,
},
{
shardingconfig.MainnetSchedule,
block3,
blockNumbered(344064),
true,
},
{
shardingconfig.TestnetSchedule,
block4,
blockNumbered(74),
false,
},
{
shardingconfig.TestnetSchedule,
block5,
blockNumbered(75),
true,
},
{
shardingconfig.TestnetSchedule,
block6,
blockNumbered(149),
false,
},
{
shardingconfig.TestnetSchedule,
block7,
blockNumbered(150),
true,
},
}

@ -641,29 +641,29 @@ func WriteStakingValidator(db DatabaseWriter, v *staking.ValidatorWrapper) error
return err
}
// ReadValidatorList retrieves staking validator by its address
func ReadValidatorList(db DatabaseReader) ([]common.Address, error) {
data, err := db.Get([]byte("validatorList"))
// ReadValidatorMap retrieves staking validator by its address
func ReadValidatorMap(db DatabaseReader) (map[common.Address]struct{}, error) {
data, err := db.Get([]byte("validatorMap"))
if len(data) == 0 || err != nil {
utils.Logger().Info().Err(err).Msg("ReadValidatorList")
utils.Logger().Info().Err(err).Msg("ReadValidatorMap")
return nil, err
}
addrs := []common.Address{}
addrs := make(map[common.Address]struct{})
if err := rlp.DecodeBytes(data, &addrs); err != nil {
utils.Logger().Error().Err(err).Msg("Unable to Decode validator List from database")
utils.Logger().Error().Err(err).Msg("Unable to Decode validator Map from database")
return nil, err
}
return addrs, nil
}
// WriteValidatorList stores staking validator's information by its address
func WriteValidatorList(db DatabaseWriter, addrs []common.Address) error {
// WriteValidatorMap stores staking validator's information by its address
func WriteValidatorMap(db DatabaseWriter, addrs map[common.Address]struct{}) error {
bytes, err := rlp.EncodeToBytes(addrs)
if err != nil {
utils.Logger().Error().Msg("[WriteValidatorList] Failed to encode")
utils.Logger().Error().Msg("[WriteValidatorMap] Failed to encode")
}
if err := db.Put([]byte("validatorList"), bytes); err != nil {
utils.Logger().Error().Msg("[WriteValidatorList] Failed to store to database")
if err := db.Put([]byte("validatorMap"), bytes); err != nil {
utils.Logger().Error().Msg("[WriteValidatorMap] Failed to store to database")
}
return err
}

@ -25,6 +25,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/staking"
)
var emptyCodeHash = crypto.Keccak256(nil)
@ -393,5 +395,10 @@ func (so *Object) Value() *big.Int {
}
// IsValidator checks whether it is a validator object
func (so *Object) IsValidator() {
func (so *Object) IsValidator(db Database) bool {
value := so.GetState(db, staking.IsValidatorKey)
if value == (common.Hash{}) {
return false
}
return true
}

@ -30,6 +30,8 @@ import (
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/staking"
stk "github.com/harmony-one/harmony/staking/types"
)
type revision struct {
@ -679,3 +681,46 @@ func (db *DB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
//log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())
return root, err
}
// GetStakingInfo update staking information of a given validator (including delegation info)
func (db *DB) GetStakingInfo(addr common.Address) *stk.ValidatorWrapper {
by := db.GetCode(addr)
if len(by) == 0 {
return nil
}
val := stk.ValidatorWrapper{}
err := rlp.DecodeBytes(by, &val)
if err != nil {
return nil
}
return &val
}
// UpdateStakingInfo update staking information of a given validator (including delegation info)
func (db *DB) UpdateStakingInfo(addr common.Address, val *stk.ValidatorWrapper) error {
by, err := rlp.EncodeToBytes(val)
if err != nil {
return err
}
db.SetCode(addr, by)
return nil
}
// SetValidatorFlag checks whether it is a validator object
func (db *DB) SetValidatorFlag(addr common.Address) {
db.SetState(addr, staking.IsValidatorKey, staking.IsValidator)
}
// UnsetValidatorFlag checks whether it is a validator object
func (db *DB) UnsetValidatorFlag(addr common.Address) {
db.SetState(addr, staking.IsValidatorKey, common.Hash{})
}
// IsValidator checks whether it is a validator object
func (db *DB) IsValidator(addr common.Address) bool {
so := db.getStateObject(addr)
if so == nil {
return false
}
return so.IsValidator(db.db)
}

@ -18,6 +18,7 @@ package core
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -29,6 +30,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
@ -179,6 +181,49 @@ 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
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, gas uint64, err error) {
msg, err := StakingToMessage(tx, header.Number())
if err != nil {
return nil, 0, err
}
// Create a new context to be used in the EVM environment
context := NewEVMContext(msg, header, bc, author)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, config, cfg)
// Apply the transaction to the current state (included in the env)
gas, err = ApplyStakingMessage(vmenv, msg, gp)
// even there is error, we charge it
if err != nil {
return nil, gas, err
}
// Update the state with pending changes
var root []byte
if config.IsS3(header.Epoch()) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsS3(header.Epoch())).Bytes()
}
*usedGas += gas
receipt = types.NewReceipt(root, false, *usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = gas
return receipt, gas, 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 {
@ -199,3 +244,25 @@ func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *bloc
}
return nil
}
// StakingToMessage returns the staking transaction as a core.Message.
// requires a signer to derive the sender.
// put it here to avoid cyclic import
func StakingToMessage(tx *staking.StakingTransaction, blockNum *big.Int) (types.Message, error) {
payload, err := tx.RLPEncodeStakeMsg()
if err != nil {
return types.Message{}, err
}
from, err := tx.SenderAddress()
if err != nil {
return types.Message{}, err
}
msg := types.NewStakingMessage(from, tx.Nonce(), tx.Gas(), tx.Price(), payload, blockNum)
stkType := tx.StakingType()
if _, ok := types.StakingTypeMap[stkType]; !ok {
return types.Message{}, staking.ErrInvalidStakingKind
}
msg.SetType(types.StakingTypeMap[stkType])
return msg, nil
}

@ -22,14 +22,18 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"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/internal/utils"
staking "github.com/harmony-one/harmony/staking/types"
)
var (
errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas")
errValidatorExist = errors.New("staking validator address already exists")
errValidatorNotExist = errors.New("staking validator address does not exist")
)
/*
@ -75,6 +79,7 @@ type Message interface {
CheckNonce() bool
Data() []byte
Type() types.TransactionType
BlockNum() *big.Int
}
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
@ -134,6 +139,11 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool,
return NewStateTransition(evm, msg, gp).TransitionDb()
}
// ApplyStakingMessage computes the new state for staking message
func ApplyStakingMessage(evm *vm.EVM, msg Message, gp *GasPool) (uint64, error) {
return NewStateTransition(evm, msg, gp).StakingTransitionDb()
}
// to returns the recipient of the message.
func (st *StateTransition) to() common.Address {
if st.msg == nil || st.msg.To() == nil /* contract creation */ {
@ -252,3 +262,105 @@ func (st *StateTransition) refundGas() {
func (st *StateTransition) gasUsed() uint64 {
return st.initialGas - st.gas
}
// StakingTransitionDb will transition the state by applying the staking message and
// returning the result including the used gas. It returns an error if failed.
// It is used for staking transaction only
func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) {
if err = st.preCheck(); err != nil {
return 0, err
}
msg := st.msg
sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsS3(st.evm.EpochNumber) // s3 includes homestead
// Pay intrinsic gas
// TODO: add new formula for staking transaction
gas, err := IntrinsicGas(st.data, false, homestead)
if err != nil {
return 0, err
}
if err = st.useGas(gas); err != nil {
return 0, err
}
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
switch msg.Type() {
case types.StakeNewVal:
stkMsg := &staking.CreateValidator{}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
break
}
err = st.applyCreateValidatorTx(stkMsg, msg.BlockNum())
case types.StakeEditVal:
stkMsg := &staking.EditValidator{}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
break
}
err = st.applyEditValidatorTx(stkMsg, msg.BlockNum())
case types.Delegate:
stkMsg := &staking.Delegate{}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
break
}
err = st.applyDelegateTx(stkMsg)
case types.Undelegate:
stkMsg := &staking.Undelegate{}
if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil {
break
}
err = st.applyUndelegateTx(stkMsg)
case types.CollectRewards:
default:
return 0, staking.ErrInvalidStakingKind
}
st.refundGas()
return st.gasUsed(), err
}
func (st *StateTransition) applyCreateValidatorTx(nv *staking.CreateValidator, blockNum *big.Int) error {
if st.state.IsValidator(nv.ValidatorAddress) {
return errValidatorExist
}
v, err := staking.CreateValidatorFromNewMsg(nv)
if err != nil {
return err
}
v.UpdateHeight = blockNum
wrapper := staking.ValidatorWrapper{*v, nil, nil, nil}
if err := st.state.UpdateStakingInfo(v.Address, &wrapper); err != nil {
return err
}
st.state.SetValidatorFlag(v.Address)
return nil
}
func (st *StateTransition) applyEditValidatorTx(ev *staking.EditValidator, blockNum *big.Int) error {
if !st.state.IsValidator(ev.ValidatorAddress) {
return errValidatorNotExist
}
wrapper := st.state.GetStakingInfo(ev.ValidatorAddress)
if err := staking.UpdateValidatorFromEditMsg(&wrapper.Validator, ev); err != nil {
return err
}
wrapper.Validator.UpdateHeight = blockNum
if err := st.state.UpdateStakingInfo(ev.ValidatorAddress, wrapper); err != nil {
return err
}
return nil
}
func (st *StateTransition) applyDelegateTx(delegate *staking.Delegate) error {
return nil
}
func (st *StateTransition) applyUndelegateTx(undelegate *staking.Undelegate) error {
return nil
}

@ -31,6 +31,7 @@ import (
"github.com/harmony-one/harmony/crypto/hash"
common2 "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types"
)
// no go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
@ -48,8 +49,18 @@ const (
SameShardTx TransactionType = iota
SubtractionOnly // only subtract tokens from source shard account
InvalidTx
StakeNewVal
StakeEditVal
Delegate
Undelegate
CollectRewards
)
// StakingTypeMap is the map from staking type to transactionType
var StakingTypeMap = map[staking.Directive]TransactionType{staking.DirectiveCreateValidator: StakeNewVal,
staking.DirectiveEditValidator: StakeEditVal, staking.DirectiveDelegate: Delegate,
staking.DirectiveUndelegate: Undelegate}
// Transaction struct.
type Transaction struct {
data txdata
@ -67,6 +78,16 @@ func (txType TransactionType) String() string {
return "SubtractionOnly"
} else if txType == InvalidTx {
return "InvalidTx"
} else if txType == StakeNewVal {
return "StakeNewValidator"
} else if txType == StakeEditVal {
return "StakeEditValidator"
} else if txType == Delegate {
return "Delegate"
} else if txType == Undelegate {
return "Undelegate"
} else if txType == CollectRewards {
return "CollectRewards"
}
return "Unknown"
}
@ -541,6 +562,7 @@ type Message struct {
gasPrice *big.Int
data []byte
checkNonce bool
blockNum *big.Int
txType TransactionType
}
@ -558,6 +580,20 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
}
}
// NewStakingMessage returns new message of staking type
// always need checkNonce
func NewStakingMessage(from common.Address, nonce uint64, gasLimit uint64, gasPrice *big.Int, data []byte, blockNum *big.Int) Message {
return Message{
from: from,
nonce: nonce,
gasLimit: gasLimit,
gasPrice: new(big.Int).Set(gasPrice),
data: data,
checkNonce: true,
blockNum: blockNum,
}
}
// From returns from address from Message.
func (m Message) From() common.Address {
return m.from
@ -608,6 +644,11 @@ func (m Message) SetType(typ TransactionType) {
m.txType = typ
}
// BlockNum returns the blockNum of the tx belongs to
func (m Message) BlockNum() *big.Int {
return m.blockNum
}
// RecentTxsStats is a recent transactions stats map tracking stats like BlockTxsCounts.
type RecentTxsStats map[uint64]BlockTxsCounts

@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core/types"
staking "github.com/harmony-one/harmony/staking/types"
)
// StateDB is an EVM database for full state querying.
@ -39,6 +40,12 @@ type StateDB interface {
SetCode(common.Address, []byte)
GetCodeSize(common.Address) int
GetStakingInfo(common.Address) *staking.ValidatorWrapper
UpdateStakingInfo(common.Address, *staking.ValidatorWrapper) error
SetValidatorFlag(common.Address)
UnsetValidatorFlag(common.Address)
IsValidator(common.Address) bool
AddRefund(uint64)
SubRefund(uint64)
GetRefund() uint64

@ -209,8 +209,8 @@ func (b *APIBackend) GetBalance(address common.Address) (*hexutil.Big, error) {
}
// GetTransactionsHistory returns list of transactions hashes of address.
func (b *APIBackend) GetTransactionsHistory(address string) ([]common.Hash, error) {
hashes, err := b.hmy.nodeAPI.GetTransactionsHistory(address)
func (b *APIBackend) GetTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
hashes, err := b.hmy.nodeAPI.GetTransactionsHistory(address, txType, order)
return hashes, err
}
@ -241,8 +241,8 @@ func (b *APIBackend) GetShardID() uint32 {
return b.hmy.shardID
}
// GetCommittee returns committee for a particular epoch.
func (b *APIBackend) GetCommittee(epoch *big.Int) (*shard.Committee, error) {
// GetValidators returns validators for a particular epoch.
func (b *APIBackend) GetValidators(epoch *big.Int) (*shard.Committee, error) {
state, err := b.hmy.BlockChain().ReadShardState(epoch)
if err != nil {
return nil, err
@ -289,3 +289,28 @@ func (b *APIBackend) SendStakingTx(
b.hmy.nodeAPI.AddPendingStakingTransaction(newStakingTx)
return nil
}
// GetCurrentValidatorAddresses returns the address of active validators for current epoch
func (b *APIBackend) GetCurrentValidatorAddresses() []common.Address {
return b.hmy.BlockChain().CurrentValidatorAddresses()
}
// GetValidatorCandidates returns the up to date validator candidates for next epoch
func (b *APIBackend) GetValidatorCandidates() []common.Address {
return b.hmy.BlockChain().ValidatorCandidates()
}
// GetValidatorInformation returns the information of validator
func (b *APIBackend) GetValidatorInformation(addr common.Address) *staking.Validator {
return b.hmy.BlockChain().ValidatorInformation(addr)
}
// GetDelegatorsInformation returns up to date information of delegators of a given validator address
func (b *APIBackend) GetDelegatorsInformation(addr common.Address) []*staking.Delegation {
return b.hmy.BlockChain().DelegatorsInformation(addr)
}
// GetValidatorStakingWithDelegation returns the amount of staking after applying all delegated stakes
func (b *APIBackend) GetValidatorStakingWithDelegation(addr common.Address) *big.Int {
return b.hmy.BlockChain().ValidatorStakingWithDelegation(addr)
}

@ -50,7 +50,7 @@ type NodeAPI interface {
AccountManager() *accounts.Manager
GetBalanceOfAddress(address common.Address) (*big.Int, error)
GetNonceOfAddress(address common.Address) uint64
GetTransactionsHistory(address string) ([]common.Hash, error)
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
IsCurrentlyLeader() bool
}

@ -32,7 +32,7 @@ const (
localnetMaxTxPoolSizeLimit = 8000
localnetMaxNumTxsPerBlockLimit = 1000
localnetRecentTxDuration = time.Hour
localnetEnableTxnThrottling = true
localnetEnableTxnThrottling = false
)
func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {

@ -34,7 +34,7 @@ const (
mainnetMaxTxPoolSizeLimit = 8000
mainnetMaxNumTxsPerBlockLimit = 1000
mainnetRecentTxDuration = time.Hour
mainnetEnableTxnThrottling = true
mainnetEnableTxnThrottling = false
// MainNetHTTPPattern is the http pattern for mainnet.
MainNetHTTPPattern = "https://api.s%d.t.hmny.io"

@ -15,11 +15,8 @@ var TestnetSchedule testnetSchedule
type testnetSchedule struct{}
const (
testnetV1Epoch = 1
testnetV2Epoch = 2
testnetEpochBlock1 = 78
threeOne = 111
// 10 minutes per epoch (at 8s/block)
testnetBlocksPerEpoch = 75
testnetVdfDifficulty = 10000 // This takes about 20s to finish the vdf
@ -28,7 +25,7 @@ const (
testnetMaxTxPoolSizeLimit = 8000
testnetMaxNumTxsPerBlockLimit = 1000
testnetRecentTxDuration = time.Hour
testnetEnableTxnThrottling = true
testnetEnableTxnThrottling = false
// TestNetHTTPPattern is the http pattern for testnet.
TestNetHTTPPattern = "https://api.s%d.b.hmny.io"
@ -38,50 +35,26 @@ const (
func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
switch {
case epoch.Cmp(big.NewInt(testnetV2Epoch)) >= 0:
return testnetV2
case epoch.Cmp(big.NewInt(testnetV1Epoch)) >= 0:
return testnetV1
default: // genesis
return testnetV0
}
}
func (testnetSchedule) BlocksPerEpoch() uint64 {
// 8 seconds per block, roughly 86400 blocks, around one day
return threeOne
return testnetBlocksPerEpoch
}
func (ts testnetSchedule) CalcEpochNumber(blockNum uint64) *big.Int {
blocks := ts.BlocksPerEpoch()
switch {
case blockNum >= testnetEpochBlock1:
return big.NewInt(int64((blockNum-testnetEpochBlock1)/blocks) + 1)
default:
return big.NewInt(0)
}
epoch := blockNum % ts.BlocksPerEpoch()
return big.NewInt(int64(epoch))
}
func (ts testnetSchedule) IsLastBlock(blockNum uint64) bool {
blocks := ts.BlocksPerEpoch()
switch {
case blockNum < testnetEpochBlock1-1:
return false
case blockNum == testnetEpochBlock1-1:
return true
default:
return ((blockNum-testnetEpochBlock1)%blocks == blocks-1)
}
return (blockNum+1)%ts.BlocksPerEpoch() == 0
}
func (ts testnetSchedule) EpochLastBlock(epochNum uint64) uint64 {
blocks := ts.BlocksPerEpoch()
switch {
case epochNum == 0:
return testnetEpochBlock1 - 1
default:
return testnetEpochBlock1 - 1 + blocks*epochNum
}
return ts.BlocksPerEpoch()*(epochNum+1) - 1
}
func (ts testnetSchedule) VdfDifficulty() int {
@ -145,8 +118,8 @@ func (ts testnetSchedule) GetShardingStructure(numShard, shardID int) []map[stri
return genShardingStructure(numShard, shardID, TestNetHTTPPattern, TestNetWSPattern)
}
var testnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(testnetV1Epoch), big.NewInt(testnetV2Epoch)}
var testnetReshardingEpoch = []*big.Int{
big.NewInt(0),
}
var testnetV0 = MustNewInstance(2, 150, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch)
var testnetV1 = MustNewInstance(2, 160, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch)
var testnetV2 = MustNewInstance(2, 170, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch)
var testnetV0 = MustNewInstance(3, 100, 80, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch)

@ -64,15 +64,20 @@ type Backend interface {
CurrentBlock() *types.Block
// Get balance
GetBalance(address common.Address) (*hexutil.Big, error)
// Get committee for a particular epoch
GetCommittee(epoch *big.Int) (*shard.Committee, error)
// Get validators for a particular epoch
GetValidators(epoch *big.Int) (*shard.Committee, error)
GetShardID() uint32
// Get transactions history for an address
GetTransactionsHistory(address string) ([]common.Hash, error)
GetTransactionsHistory(address, txType, order string) ([]common.Hash, error)
// retrieve the blockHash using txID and add blockHash to CxPool for resending
ResendCx(ctx context.Context, txID common.Hash) (uint64, bool)
IsLeader() bool
SendStakingTx(ctx context.Context, newStakingTx *staking.StakingTransaction) error
GetCurrentValidatorAddresses() []common.Address
GetValidatorCandidates() []common.Address
GetValidatorInformation(addr common.Address) *staking.Validator
GetDelegatorsInformation(addr common.Address) []*staking.Delegation
GetValidatorStakingWithDelegation(addr common.Address) *big.Int
}
// GetAPIs returns all the APIs.

@ -4,8 +4,6 @@ import (
"context"
"fmt"
"github.com/harmony-one/harmony/common/denominations"
"math/big"
"time"
@ -13,16 +11,21 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_bls "github.com/harmony-one/harmony/crypto/bls"
internal_common "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
)
const (
defaultGasPrice = denominations.Nano
defaultFromAddress = "0x0000000000000000000000000000000000000000"
defaultGasPrice = denominations.Nano
defaultFromAddress = "0x0000000000000000000000000000000000000000"
defaultBlocksPeriod = 15000
)
// PublicBlockChainAPI provides an API to access the Harmony blockchain.
@ -36,12 +39,28 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
return &PublicBlockChainAPI{b}
}
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
// BlockArgs is struct to include optional block formatting params.
type BlockArgs struct {
WithSigners bool `json:"withSigners"`
InclTx bool `json:"inclTx"`
FullTx bool `json:"fullTx"`
Signers []string `json:"signers"`
}
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx in BlockArgs is true all
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned. When withSigners in BlocksArgs is true
// it shows block signers for this block in list of one addresses.
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, blockArgs BlockArgs) (map[string]interface{}, error) {
block, err := s.b.BlockByNumber(ctx, blockNr)
blockArgs.InclTx = true
if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, blockNr)
if err != nil {
return nil, err
}
}
if block != nil {
response, err := RPCMarshalBlock(block, true, fullTx)
response, err := RPCMarshalBlock(block, blockArgs)
if err == nil && blockNr == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
@ -55,17 +74,50 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
// detail, otherwise only the transaction hash is returned.
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, blockArgs BlockArgs) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash)
blockArgs.InclTx = true
if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(block.NumberU64()))
if err != nil {
return nil, err
}
}
if block != nil {
return RPCMarshalBlock(block, true, fullTx)
return RPCMarshalBlock(block, blockArgs)
}
return nil, err
}
// GetCommittee returns committee for a particular epoch.
func (s *PublicBlockChainAPI) GetCommittee(ctx context.Context, epoch int64) (map[string]interface{}, error) {
committee, err := s.b.GetCommittee(big.NewInt(epoch))
// GetBlocks method returns blocks in range blockStart, blockEnd just like GetBlockByNumber but all at once.
func (s *PublicBlockChainAPI) GetBlocks(ctx context.Context, blockStart rpc.BlockNumber, blockEnd rpc.BlockNumber, blockArgs BlockArgs) ([]map[string]interface{}, error) {
result := make([]map[string]interface{}, 0)
for i := blockStart; i <= blockEnd; i++ {
block, err := s.b.BlockByNumber(ctx, i)
blockArgs.InclTx = true
if blockArgs.WithSigners {
blockArgs.Signers, err = s.GetBlockSigners(ctx, rpc.BlockNumber(i))
if err != nil {
return nil, err
}
}
if block != nil {
rpcBlock, err := RPCMarshalBlock(block, blockArgs)
if err == nil && i == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
rpcBlock[field] = nil
}
}
result = append(result, rpcBlock)
}
}
return result, nil
}
// GetValidators returns validators list for a particular epoch.
func (s *PublicBlockChainAPI) GetValidators(ctx context.Context, epoch int64) (map[string]interface{}, error) {
committee, err := s.b.GetValidators(big.NewInt(epoch))
if err != nil {
return nil, err
}
@ -93,11 +145,184 @@ func (s *PublicBlockChainAPI) GetCommittee(ctx context.Context, epoch int64) (ma
return result, nil
}
// GetBlockSigners returns signers for a particular block.
func (s *PublicBlockChainAPI) GetBlockSigners(ctx context.Context, blockNr rpc.BlockNumber) ([]string, error) {
if uint64(blockNr) == 0 {
return make([]string, 0), nil
}
block, err := s.b.BlockByNumber(ctx, blockNr)
if err != nil {
return nil, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
if err != nil {
return nil, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return nil, err
}
pubkeys := make([]*bls.PublicKey, len(committee.NodeList))
for i, validator := range committee.NodeList {
pubkeys[i] = new(bls.PublicKey)
validator.BlsPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
result := make([]string, 0)
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return result, err
}
if err != nil {
return result, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return result, err
}
for _, validator := range committee.NodeList {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return result, err
}
blsPublicKey := new(bls.PublicKey)
validator.BlsPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
result = append(result, oneAddress)
}
}
return result, nil
}
// IsBlockSigner returns true if validator with address signed blockNr block.
func (s *PublicBlockChainAPI) IsBlockSigner(ctx context.Context, blockNr rpc.BlockNumber, address string) (bool, error) {
block, err := s.b.BlockByNumber(ctx, blockNr)
if err != nil {
return false, err
}
blockWithSigners, err := s.b.BlockByNumber(ctx, blockNr+1)
if err != nil {
return false, err
}
committee, err := s.b.GetValidators(block.Epoch())
if err != nil {
return false, err
}
pubkeys := make([]*bls.PublicKey, len(committee.NodeList))
for i, validator := range committee.NodeList {
pubkeys[i] = new(bls.PublicKey)
validator.BlsPublicKey.ToLibBLSPublicKey(pubkeys[i])
}
mask, err := internal_bls.NewMask(pubkeys, nil)
if err != nil {
return false, err
}
err = mask.SetMask(blockWithSigners.Header().LastCommitBitmap())
if err != nil {
return false, err
}
for _, validator := range committee.NodeList {
oneAddress, err := internal_common.AddressToBech32(validator.EcdsaAddress)
if err != nil {
return false, err
}
if oneAddress != address {
continue
}
blsPublicKey := new(bls.PublicKey)
validator.BlsPublicKey.ToLibBLSPublicKey(blsPublicKey)
if ok, err := mask.KeyEnabled(blsPublicKey); err == nil && ok {
return true, nil
}
}
return false, nil
}
// GetSignedBlocks returns how many blocks a particular validator signed for last defaultBlocksPeriod (3 hours ~ 1500 blocks).
func (s *PublicBlockChainAPI) GetSignedBlocks(ctx context.Context, address string) hexutil.Uint64 {
header := s.LatestHeader(ctx)
totalSigned := uint64(0)
lastBlock := uint64(0)
if header.BlockNumber >= defaultBlocksPeriod {
lastBlock = header.BlockNumber - defaultBlocksPeriod + 1
}
for i := header.BlockNumber; i >= lastBlock; i-- {
signed, err := s.IsBlockSigner(ctx, rpc.BlockNumber(i), address)
if err == nil && signed {
totalSigned++
}
}
return hexutil.Uint64(totalSigned)
}
// GetEpoch returns current epoch.
func (s *PublicBlockChainAPI) GetEpoch(ctx context.Context) hexutil.Uint64 {
return hexutil.Uint64(s.LatestHeader(ctx).Epoch)
}
// GetLeader returns current shard leader.
func (s *PublicBlockChainAPI) GetLeader(ctx context.Context) string {
return s.LatestHeader(ctx).Leader
}
// GetValidatorInformation returns full validator info.
func (s *PublicBlockChainAPI) GetValidatorInformation(ctx context.Context, address string) (map[string]interface{}, error) {
validator := s.b.GetValidatorInformation(internal_common.ParseAddr(address))
fields := map[string]interface{}{
"address": validator.Address.String(),
"stake": hexutil.Uint64(validator.Stake.Uint64()),
"name": validator.Description.Name,
"validatingPublicKey": validator.SlotPubKeys,
"unbondingHeight": hexutil.Uint64(validator.UnbondingHeight.Uint64()),
"minSelfDelegation": hexutil.Uint64(validator.MinSelfDelegation.Uint64()),
"active": validator.Active,
"identity": validator.Description.Identity,
"commissionRate": hexutil.Uint64(validator.Commission.CommissionRates.Rate.Int.Uint64()),
"commissionUpdateHeight": hexutil.Uint64(validator.Commission.UpdateHeight.Uint64()),
"commissionMaxRate": hexutil.Uint64(validator.Commission.CommissionRates.MaxRate.Uint64()),
"commissionMaxChangeRate": hexutil.Uint64(validator.Commission.CommissionRates.MaxChangeRate.Uint64()),
"website": validator.Description.Website,
"securityContact": validator.Description.SecurityContact,
"details": validator.Description.Details,
}
return fields, nil
}
// GetStake returns validator stake.
func (s *PublicBlockChainAPI) GetStake(ctx context.Context, address string) hexutil.Uint64 {
validator := s.b.GetValidatorInformation(internal_common.ParseAddr(address))
return hexutil.Uint64(validator.Stake.Uint64())
}
// GetValidatorStakingAddress stacking address returns validator stacking address.
func (s *PublicBlockChainAPI) GetValidatorStakingAddress(ctx context.Context, address string) string {
validator := s.b.GetValidatorInformation(internal_common.ParseAddr(address))
return validator.Address.String()
}
// GetValidatorStakingWithDelegation returns total balace stacking for validator with delegation.
func (s *PublicBlockChainAPI) GetValidatorStakingWithDelegation(ctx context.Context, address string) hexutil.Uint64 {
return hexutil.Uint64(s.b.GetValidatorStakingWithDelegation(internal_common.ParseAddr(address)).Uint64())
}
// GetDelegatorsInformation returns list of delegators for a validator address.
func (s *PublicBlockChainAPI) GetDelegatorsInformation(ctx context.Context, address string) ([]map[string]interface{}, error) {
delegators := s.b.GetDelegatorsInformation(internal_common.ParseAddr(address))
delegatorsFields := make([]map[string]interface{}, 0)
for _, delegator := range delegators {
fields := map[string]interface{}{
"delegator": delegator.DelegatorAddress.String(),
"amount": hexutil.Uint64(delegator.Amount.Uint64()),
}
delegatorsFields = append(delegatorsFields, fields)
}
return delegatorsFields, nil
}
// GetShardingStructure returns an array of sharding structures.
func (s *PublicBlockChainAPI) GetShardingStructure(ctx context.Context) ([]map[string]interface{}, error) {
// Get header and number of shards.
header := s.b.CurrentBlock().Header()
numShard := core.ShardingSchedule.InstanceForEpoch(header.Epoch()).NumShards()
epoch := s.GetEpoch(ctx)
numShard := core.ShardingSchedule.InstanceForEpoch(big.NewInt(int64(epoch))).NumShards()
// Return shareding structure for each case.
return core.ShardingSchedule.GetShardingStructure(int(numShard), int(s.b.GetShardID())), nil

@ -27,6 +27,8 @@ type TxHistoryArgs struct {
PageIndex int `json:"pageIndex"`
PageSize int `json:"pageSize"`
FullTx bool `json:"fullTx"`
TxType string `json:"txType"`
Order string `json:"order"`
}
// PublicTransactionPoolAPI exposes methods for the RPC interface
@ -44,19 +46,17 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa
func (s *PublicTransactionPoolAPI) GetTransactionsHistory(ctx context.Context, args TxHistoryArgs) (map[string]interface{}, error) {
address := args.Address
result := []common.Hash{}
if strings.HasPrefix(address, "one1") {
hashes, err := s.b.GetTransactionsHistory(address)
var err error
if strings.HasPrefix(args.Address, "one1") {
address = args.Address
} else {
addr := internal_common.ParseAddr(args.Address)
address, err = internal_common.AddressToBech32(addr)
if err != nil {
return nil, err
}
result = ReturnWithPagination(hashes, args)
}
addr := internal_common.ParseAddr(address)
oneAddress, err := internal_common.AddressToBech32(addr)
if err != nil {
return nil, err
}
hashes, err := s.b.GetTransactionsHistory(oneAddress)
hashes, err := s.b.GetTransactionsHistory(address, args.TxType, args.Order)
if err != nil {
return nil, err
}

@ -192,12 +192,13 @@ type RPCBlock struct {
Transactions []interface{} `json:"transactions"`
Uncles []common.Hash `json:"uncles"`
TotalDifficulty *big.Int `json:"totalDifficulty"`
Signers []string `json:"signers"`
}
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes.
func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
func RPCMarshalBlock(b *types.Block, blockArgs BlockArgs) (map[string]interface{}, error) {
head := b.Header() // copies the header once
fields := map[string]interface{}{
"number": (*hexutil.Big)(head.Number()),
@ -218,11 +219,11 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter
"receiptsRoot": head.ReceiptHash(),
}
if inclTx {
if blockArgs.InclTx {
formatTx := func(tx *types.Transaction) (interface{}, error) {
return tx.Hash(), nil
}
if fullTx {
if blockArgs.FullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) {
return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
}
@ -244,7 +245,9 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter
uncleHashes[i] = uncle.Hash()
}
fields["uncles"] = uncleHashes
if blockArgs.WithSigners {
fields["signers"] = blockArgs.Signers
}
return fields, nil
}

@ -34,9 +34,9 @@ var (
// TestnetChainConfig contains the chain parameters to run a node on the harmony test network.
TestnetChainConfig = &ChainConfig{
ChainID: TestnetChainID,
CrossTxEpoch: big.NewInt(1),
CrossLinkEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(3),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: EpochTBD,
StakingEpoch: EpochTBD,
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
}

@ -349,15 +349,11 @@ func (node *Node) AddPendingReceipts(receipts *types.CXReceiptsProof) {
// Take out a subset of valid transactions from the pending transaction list
// Note the pending transaction list will then contain the rest of the txs
func (node *Node) getTransactionsForNewBlock(
coinbase common.Address,
) types.Transactions {
func (node *Node) getTransactionsForNewBlock(coinbase common.Address) (types.Transactions, staking.StakingTransactions) {
txsThrottleConfig := core.ShardingSchedule.TxsThrottleConfig()
// the next block number to be added in consensus protocol, which is always one more than current chain header block
newBlockNum := node.Blockchain().CurrentBlock().NumberU64() + 1
// remove old (> txsThrottleConfigRecentTxDuration) blockNum keys from recentTxsStats and initiailize for the new block
for blockNum := range node.recentTxsStats {
recentTxsBlockNumGap := uint64(txsThrottleConfig.RecentTxDuration / node.BlockPeriod)
@ -366,23 +362,20 @@ func (node *Node) getTransactionsForNewBlock(
}
}
node.recentTxsStats[newBlockNum] = make(types.BlockTxsCounts)
// Must update to the correct current state before processing potential txns
if err := node.Worker.UpdateCurrent(coinbase); err != nil {
utils.Logger().Error().
Err(err).
Msg("Failed updating worker's state before txn selection")
return types.Transactions{}
return types.Transactions{}, staking.StakingTransactions{}
}
node.pendingTxMutex.Lock()
defer node.pendingTxMutex.Unlock()
node.pendingStakingTxMutex.Lock()
defer node.pendingStakingTxMutex.Unlock()
pendingTransactions := types.Transactions{}
pendingStakingTransactions := staking.StakingTransactions{}
for _, tx := range node.pendingTransactions {
pendingTransactions = append(pendingTransactions, tx)
}
@ -392,6 +385,9 @@ func (node *Node) getTransactionsForNewBlock(
selected, unselected, invalid := node.Worker.SelectTransactionsForNewBlock(newBlockNum, pendingTransactions, 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 {
node.pendingTransactions[unselectedTx.Hash()] = unselectedTx
@ -402,7 +398,17 @@ func (node *Node) getTransactionsForNewBlock(
Int("invalidDiscarded", len(invalid)).
Msg("Selecting Transactions")
return selected
node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
for _, unselectedStakingTx := range unselectedStaking {
node.pendingStakingTransactions[unselectedStakingTx.Hash()] = unselectedStakingTx
}
utils.Logger().Info().
Int("remainPending", len(node.pendingStakingTransactions)).
Int("selected", len(unselectedStaking)).
Int("invalidDiscarded", len(invalidStaking)).
Msg("Selecting Transactions")
return selected, selectedStaking
}
func (node *Node) startRxPipeline(

@ -2,6 +2,7 @@ package node
import (
"encoding/binary"
"sort"
"sync"
"github.com/ethereum/go-ethereum/common"
@ -146,7 +147,7 @@ func (node *Node) commitBlockForExplorer(block *types.Block) {
}
// GetTransactionsHistory returns list of transactions hashes of address.
func (node *Node) GetTransactionsHistory(address string) ([]common.Hash, error) {
func (node *Node) GetTransactionsHistory(address, txType, order string) ([]common.Hash, error) {
addressData := &explorer.Address{}
key := explorer.GetAddressKey(address)
bytes, err := explorer.GetStorageInstance(node.SelfPeer.IP, node.SelfPeer.Port, false).GetDB().Get([]byte(key))
@ -157,10 +158,21 @@ func (node *Node) GetTransactionsHistory(address string) ([]common.Hash, error)
utils.Logger().Error().Err(err).Msg("[Explorer] Cannot convert address data from DB")
return nil, err
}
if order == "DESC" {
sort.Slice(addressData.TXs[:], func(i, j int) bool {
return addressData.TXs[i].Timestamp > addressData.TXs[j].Timestamp
})
} else {
sort.Slice(addressData.TXs[:], func(i, j int) bool {
return addressData.TXs[i].Timestamp < addressData.TXs[j].Timestamp
})
}
hashes := make([]common.Hash, 0)
for _, tx := range addressData.TXs {
hash := common.HexToHash(tx.ID)
hashes = append(hashes, hash)
if txType == "" || txType == "ALL" || txType == tx.Type {
hash := common.HexToHash(tx.ID)
hashes = append(hashes, hash)
}
}
return hashes, nil
}

@ -409,7 +409,7 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block, commitSigAndBit
// AddNewBlock is usedd to add new block into the blockchain.
func (node *Node) AddNewBlock(newBlock *types.Block) error {
_, err := node.Blockchain().InsertChain([]*types.Block{newBlock})
_, err := node.Blockchain().InsertChain([]*types.Block{newBlock}, true /* verifyHeaders */)
if err != nil {
utils.Logger().Error().
Err(err).

@ -33,8 +33,8 @@ func TestAddNewBlock(t *testing.T) {
nodeconfig.SetNetworkType(nodeconfig.Devnet)
node := New(host, consensus, testDBFactory, false)
selectedTxs := node.getTransactionsForNewBlock(common.Address{})
node.Worker.CommitTransactions(selectedTxs, common.Address{})
selectedTxs, stks := node.getTransactionsForNewBlock(common.Address{})
node.Worker.CommitTransactions(selectedTxs, stks, common.Address{})
block, _ := node.Worker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
err = node.AddNewBlock(block)
@ -65,8 +65,8 @@ func TestVerifyNewBlock(t *testing.T) {
}
node := New(host, consensus, testDBFactory, false)
selectedTxs := node.getTransactionsForNewBlock(common.Address{})
node.Worker.CommitTransactions(selectedTxs, common.Address{})
selectedTxs, stks := node.getTransactionsForNewBlock(common.Address{})
node.Worker.CommitTransactions(selectedTxs, stks, common.Address{})
block, _ := node.Worker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
if err := node.VerifyNewBlock(block); err != nil {

@ -81,9 +81,9 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
coinbase := node.Consensus.SelfAddress
// Prepare transactions including staking transactions
selectedTxs := node.getTransactionsForNewBlock(coinbase)
selectedTxs, selectedStakingTxs := node.getTransactionsForNewBlock(coinbase)
if err := node.Worker.CommitTransactions(selectedTxs, coinbase); err != nil {
if err := node.Worker.CommitTransactions(selectedTxs, selectedStakingTxs, coinbase); err != nil {
ctxerror.Log15(utils.GetLogger().Error,
ctxerror.New("cannot commit transactions").
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"
@ -61,17 +62,17 @@ func (w *Worker) throttleTxs(selected types.Transactions, recentTxsStats types.R
sender = msg.From()
}
// do not throttle transactions if disabled
if !txsThrottleConfig.EnableTxnThrottling {
return sender, shardingconfig.TxSelect
}
// already selected max num txs
if len(selected) > txsThrottleConfig.MaxNumTxsPerBlockLimit {
utils.Logger().Info().Str("txId", tx.Hash().Hex()).Int("MaxNumTxsPerBlockLimit", txsThrottleConfig.MaxNumTxsPerBlockLimit).Msg("Throttling tx with max num txs per block limit")
return sender, shardingconfig.TxUnselect
}
// do not throttle transactions if disabled
if !txsThrottleConfig.EnableTxnThrottling {
return sender, shardingconfig.TxSelect
}
// throttle a single sender sending too many transactions in one block
if tx.Value().Cmp(txsThrottleConfig.MaxTxAmountLimit) > 0 {
utils.Logger().Info().Str("txId", tx.Hash().Hex()).Uint64("MaxTxAmountLimit", txsThrottleConfig.MaxTxAmountLimit.Uint64()).Uint64("txAmount", tx.Value().Uint64()).Msg("Throttling tx with max amount limit")
@ -107,6 +108,13 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
continue
}
// If we don't have enough gas for any further transactions then we're done
if w.current.gasPool.Gas() < params.TxGas {
utils.Logger().Info().Str("Not enough gas for further transactions, have", w.current.gasPool.String()).Uint64("want", params.TxGas)
unselected = append(unselected, tx)
continue
}
sender, flag := w.throttleTxs(selected, recentTxsStats, txsThrottleConfig, tx)
switch flag {
case shardingconfig.TxUnselect:
@ -116,17 +124,21 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
invalid = append(invalid, tx)
case shardingconfig.TxSelect:
snap := w.current.state.Snapshot()
_, err := w.commitTransaction(tx, coinbase)
if err != nil {
w.current.state.RevertToSnapshot(snap)
if tx.GasPrice().Uint64() == 0 {
invalid = append(invalid, tx)
utils.Logger().Error().Err(err).Str("txId", tx.Hash().Hex()).Msg("Commit transaction error")
} else {
selected = append(selected, tx)
// handle the case when msg was not able to extracted from tx
if len(sender.String()) > 0 {
recentTxsStats[newBlockNum][sender]++
snap := w.current.state.Snapshot()
_, err := w.commitTransaction(tx, coinbase)
if err != nil {
w.current.state.RevertToSnapshot(snap)
invalid = append(invalid, tx)
utils.Logger().Error().Err(err).Str("txId", tx.Hash().Hex()).Msg("Commit transaction error")
} else {
selected = append(selected, tx)
// handle the case when msg was not able to extracted from tx
if len(sender.String()) > 0 {
recentTxsStats[newBlockNum][sender]++
}
}
}
}
@ -139,11 +151,77 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra
utils.Logger().Info().Str("txId", tx.Hash().Hex()).Uint64("txGasLimit", tx.Gas()).Msg("Transaction gas limit info")
}
utils.Logger().Info().Uint64("newBlockNum", newBlockNum).Uint64("blockGasLimit", w.current.header.GasLimit()).Uint64("blockGasUsed", w.current.header.GasUsed()).Msg("Block gas limit and usage info")
utils.Logger().Info().Uint64("newBlockNum", newBlockNum).Int("newTxns", len(selected)).Uint64("blockGasLimit", w.current.header.GasLimit()).Uint64("blockGasUsed", w.current.header.GasUsed()).Msg("Block gas limit and usage info")
return selected, unselected, invalid
}
// SelectStakingTransactionsForNewBlock selects staking transactions for new block.
func (w *Worker) SelectStakingTransactionsForNewBlock(
newBlockNum uint64, txs staking.StakingTransactions,
coinbase common.Address) (staking.StakingTransactions, staking.StakingTransactions, staking.StakingTransactions) {
// only beaconchain process staking transaction
if w.chain.ShardID() != values.BeaconChainShardID {
return nil, nil, nil
}
// TODO: gas pool should be initialized once for both normal and staking transactions
// 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")
}
err = w.chain.UpdateValidatorMap(tx)
// keep offchain database consistency with onchain we need revert
// but it should not happend unless local database corrupted
if err != nil {
w.current.state.RevertToSnapshot(snap)
return nil, err
}
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) {
snap := w.current.state.Snapshot()
@ -152,6 +230,7 @@ func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
w.current.header.SetGasUsed(gasUsed)
if err != nil {
w.current.state.RevertToSnapshot(snap)
utils.Logger().Error().Err(err).Str("stakingTxId", tx.Hash().Hex()).Msg("Offchain ValidatorMap Read/Write Error")
return nil, err
}
if receipt == nil {
@ -167,9 +246,8 @@ func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
return receipt.Logs, nil
}
// CommitTransactions commits transactions including staking transactions.
func (w *Worker) CommitTransactions(
txs types.Transactions, coinbase common.Address) error {
// CommitTransactions commits transactions.
func (w *Worker) CommitTransactions(txs types.Transactions, stakingTxns staking.StakingTransactions, coinbase common.Address) error {
// Must update to the correct current state before processing potential txns
if err := w.UpdateCurrent(coinbase); err != nil {
utils.Logger().Error().
@ -190,6 +268,10 @@ func (w *Worker) CommitTransactions(
}
}
for _, stakingTx := range stakingTxns {
_ = stakingTx
// TODO: add logic to commit staking txns
}
return nil
}
@ -331,40 +413,16 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi
}
}
stks, _, err := w.UpdateStakeInformation()
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,
stks,
)
block, err := w.engine.Finalize(w.chain, copyHeader, s, w.current.txs, w.current.receipts, w.current.outcxs, w.current.incxs, w.current.stkingTxs)
if err != nil {
return nil, ctxerror.New("cannot finalize block").WithCause(err)
}
return block, nil
}
// UpdateStakeInformation updates validator and its delegation information
func (w *Worker) UpdateStakeInformation() ([]*staking.StakingTransaction, []*staking.ValidatorWrapper, error) {
// node.pendingStakingTransactions = make(map[common.Hash]*staking.StakingTransaction)
// for _, unselectedStakingTx := range unselectedStaking {
// node.pendingStakingTransactions[unselectedStakingTx.Hash()] = unselectedStakingTx
// }
addrs, err := w.chain.ReadValidatorList()
if err != nil {
return nil, nil, err
}
//validatorInfo := []staking.ValidatorWrapper{}
for _, addr := range addrs {
_ = addr
}
return nil, nil, nil
}
// New create a new worker object.
func New(config *params.ChainConfig, chain *core.BlockChain, engine consensus_engine.Engine) *Worker {
worker := &Worker{
@ -373,8 +431,8 @@ func New(config *params.ChainConfig, chain *core.BlockChain, engine consensus_en
chain: chain,
engine: engine,
}
worker.gasFloor = 500000000000000000
worker.gasCeil = 1000000000000000000
worker.gasFloor = 80000000
worker.gasCeil = 120000000
parent := worker.chain.CurrentBlock()
num := parent.Number()

@ -74,7 +74,7 @@ func TestCommitTransactions(t *testing.T) {
tx, _ := types.SignTx(types.NewTransaction(baseNonce, testBankAddress, uint32(0), big.NewInt(int64(denominations.One*randAmount)), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
// Commit the tx to the worker
err := worker.CommitTransactions(types.Transactions{tx}, testBankAddress)
err := worker.CommitTransactions(types.Transactions{tx}, nil, testBankAddress)
if err != nil {
t.Error(err)
}

@ -0,0 +1,18 @@
package staking
import (
"github.com/ethereum/go-ethereum/crypto"
)
const (
isValidatorKeyStr = "Harmony/IsValidator/v0"
isValidatorStr = "Harmony/IsAValidator/v0"
isNotValidatorStr = "Harmony/IsNotAValidator/v0"
)
// keys used to retrieve staking related informatio
var (
IsValidatorKey = crypto.Keccak256Hash([]byte(isValidatorKeyStr))
IsValidator = crypto.Keccak256Hash([]byte(isValidatorStr))
IsNotValidator = crypto.Keccak256Hash([]byte(isNotValidatorStr))
)

@ -1,249 +1,72 @@
package types
import (
"fmt"
"errors"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/internal/common"
)
// DVPair is struct that just has a delegator-validator pair with no other data.
// It is intended to be used as a marshalable pointer. For example, a DVPair can be used to construct the
// key to getting an UnbondingDelegation from state.
type DVPair struct {
DelegatorAddress common.Address
ValidatorAddress common.Address
}
// DVVTriplet is struct that just has a delegator-validator-validator triplet with no other data.
// It is intended to be used as a marshalable pointer. For example, a DVVTriplet can be used to construct the
// key to getting a Redelegation from state.
type DVVTriplet struct {
DelegatorAddress common.Address
ValidatorSrcAddress common.Address
ValidatorDstAddress common.Address
}
var (
errInsufficientBalance = errors.New("Insufficient balance to undelegate")
errInvalidAmount = errors.New("Invalid amount, must be positive")
)
// Delegation represents the bond with tokens held by an account. It is
// owned by one delegator, and is associated with the voting power of one
// validator.
type Delegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"`
Amount *big.Int `json:"amount" yaml:"amount"`
Entries []*UndelegationEntry `json:"entries" yaml:"entries"`
}
// UndelegationEntry represents one undelegation entry
type UndelegationEntry struct {
Amount *big.Int
Epoch *big.Int
}
// NewDelegation creates a new delegation object
func NewDelegation(delegatorAddr common.Address, validatorAddr common.Address,
func NewDelegation(delegatorAddr common.Address,
amount *big.Int) Delegation {
return Delegation{
DelegatorAddress: delegatorAddr,
ValidatorAddress: validatorAddr,
Amount: amount,
}
}
// MarshalDelegation return the delegation
func MarshalDelegation(delegation Delegation) ([]byte, error) {
return rlp.EncodeToBytes(delegation)
}
// UnmarshalDelegation return the delegation
func UnmarshalDelegation(by []byte) (*Delegation, error) {
decoded := &Delegation{}
err := rlp.DecodeBytes(by, decoded)
return decoded, err
}
// GetDelegatorAddr returns DelegatorAddr
func (d Delegation) GetDelegatorAddr() common.Address { return d.DelegatorAddress }
// GetValidatorAddr returns ValidatorAddr
func (d Delegation) GetValidatorAddr() common.Address { return d.ValidatorAddress }
// GetAmount returns amount of a delegation
func (d Delegation) GetAmount() *big.Int { return d.Amount }
// String returns a human readable string representation of a Delegation.
func (d Delegation) String() string {
return fmt.Sprintf(`
Delegation:
Delegator: %s
Validator: %s
Amount: %s
`, d.DelegatorAddress, d.ValidatorAddress, d.Amount)
}
// Delegations is a collection of delegations
type Delegations []Delegation
// String returns the string representation of a list of delegations
func (d Delegations) String() (out string) {
for _, del := range d {
out += del.String() + "\n"
}
return strings.TrimSpace(out)
}
// UnbondingDelegation stores all of a single delegator's unbonding bonds
// for a single validator in an time-ordered list
type UnbondingDelegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"` // validator unbonding from operator addr
Entries []UnbondingDelegationEntry `json:"entries" yaml:"entries"` // unbonding delegation entries
}
// UnbondingDelegationEntry - entry to an UnbondingDelegation
type UnbondingDelegationEntry struct {
ExitEpoch *big.Int `json:"exit_epoch" yaml:"exit_epoch"` // epoch which the unbonding begins
Amount *big.Int `json:"amount" yaml:"amount"` // atoms to receive at completion
}
// NewUnbondingDelegation - create a new unbonding delegation object
func NewUnbondingDelegation(delegatorAddr common.Address,
validatorAddr common.Address, epoch *big.Int, amt *big.Int) UnbondingDelegation {
entry := NewUnbondingDelegationEntry(epoch, amt)
return UnbondingDelegation{
DelegatorAddress: delegatorAddr,
ValidatorAddress: validatorAddr,
Entries: []UnbondingDelegationEntry{entry},
// AddEntry - append entry to the undelegation
func (d *Delegation) AddEntry(epoch *big.Int, amt *big.Int) error {
if d.Amount.Cmp(amt) < 0 {
return errInsufficientBalance
}
}
// NewUnbondingDelegationEntry - create a new unbonding delegation object
func NewUnbondingDelegationEntry(epoch *big.Int, amt *big.Int) UnbondingDelegationEntry {
return UnbondingDelegationEntry{
ExitEpoch: epoch,
Amount: amt,
if amt.Sign() <= 0 {
return errInvalidAmount
}
}
d.Amount.Sub(d.Amount, amt)
// AddEntry - append entry to the unbonding delegation
// if there exists same ExitEpoch entry, merge the amount
// TODO: check the total amount not exceed the staking amount call this function
func (d *UnbondingDelegation) AddEntry(epoch *big.Int, amt *big.Int) {
entry := NewUnbondingDelegationEntry(epoch, amt)
for i := range d.Entries {
if d.Entries[i].ExitEpoch == entry.ExitEpoch {
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount)
return
for _, entry := range d.Entries {
if entry.Epoch.Cmp(epoch) == 0 {
entry.Amount.Add(entry.Amount, amt)
return nil
}
}
// same exit epoch entry not found
d.Entries = append(d.Entries, entry)
return
item := UndelegationEntry{amt, epoch}
d.Entries = append(d.Entries, &item)
return nil
}
// String returns a human readable string representation of an UnbondingDelegation.
func (d UnbondingDelegation) String() string {
out := fmt.Sprintf(`Unbonding Delegations between:
Delegator: %s
Validator: %s
Entries:`, d.DelegatorAddress, d.ValidatorAddress)
// DeleteEntry - delete an entry from the undelegation
// Opimize it
func (d *Delegation) DeleteEntry(epoch *big.Int) {
entries := []*UndelegationEntry{}
for i, entry := range d.Entries {
out += fmt.Sprintf(` Unbonding Delegation %d:
ExitEpoch: %v
Amount: %s`, i, entry.ExitEpoch, entry.Amount)
}
return out
}
// UnbondingDelegations is a collection of UnbondingDelegation
type UnbondingDelegations []UnbondingDelegation
func (ubds UnbondingDelegations) String() (out string) {
for _, u := range ubds {
out += u.String() + "\n"
}
return strings.TrimSpace(out)
}
// Redelegation contains the list of a particular delegator's
// redelegating bonds from a particular source validator to a
// particular destination validator
type Redelegation struct {
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
ValidatorSrcAddress common.Address `json:"validator_src_address" yaml:"validator_src_address"` // validator redelegation source operator addr
ValidatorDstAddress common.Address `json:"validator_dst_address" yaml:"validator_dst_address"` // validator redelegation destination operator addr
Entries []RedelegationEntry `json:"entries" yaml:"entries"` // redelegation entries
}
// RedelegationEntry - entry to a Redelegation
type RedelegationEntry struct {
Epoch *big.Int `json:"epoch" yaml:"epoch"` // epoch at which the redelegation took place
Amount *big.Int `json:"amount" yaml:"amount"` // amount of destination-validator tokens created by redelegation
}
// NewRedelegation - create a new redelegation object
func NewRedelegation(delegatorAddr common.Address, validatorSrcAddr,
validatorDstAddr common.Address, epoch *big.Int, amt *big.Int) Redelegation {
entry := NewRedelegationEntry(epoch, amt)
return Redelegation{
DelegatorAddress: delegatorAddr,
ValidatorSrcAddress: validatorSrcAddr,
ValidatorDstAddress: validatorDstAddr,
Entries: []RedelegationEntry{entry},
}
}
// NewRedelegationEntry - create a new redelegation object
func NewRedelegationEntry(epoch *big.Int, amt *big.Int) RedelegationEntry {
return RedelegationEntry{
Epoch: epoch,
Amount: amt,
}
}
// AddEntry - append entry to the unbonding delegation
// Merge if has same epoch field
func (d *Redelegation) AddEntry(epoch *big.Int, amt *big.Int) {
entry := NewRedelegationEntry(epoch, amt)
for i := range d.Entries {
if d.Entries[i].Epoch == entry.Epoch {
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount)
return
if entry.Epoch.Cmp(epoch) == 0 {
entries = append(d.Entries[:i], d.Entries[i+1:]...)
}
}
// same epoch entry not found
d.Entries = append(d.Entries, entry)
return
}
// String returns a human readable string representation of a Redelegation.
func (d Redelegation) String() string {
out := fmt.Sprintf(`
Redelegations between:
Delegator: %s
Source Validator: %s
Destination Validator: %s
Entries:
`,
d.DelegatorAddress, d.ValidatorSrcAddress, d.ValidatorDstAddress,
)
for i, entry := range d.Entries {
out += fmt.Sprintf(` Redelegation Entry #%d:
Epoch: %v
Amount: %v
`,
i, entry.Epoch, entry.Amount,
)
}
return strings.TrimRight(out, "\n")
}
// Redelegations are a collection of Redelegation
type Redelegations []Redelegation
func (d Redelegations) String() (out string) {
for _, red := range d {
out += red.String() + "\n"
if entries != nil {
d.Entries = entries
}
return strings.TrimSpace(out)
}

@ -4,11 +4,10 @@ import (
"fmt"
"math/big"
"github.com/harmony-one/harmony/shard"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
"github.com/pkg/errors"
)
@ -22,8 +21,6 @@ const (
DirectiveEditValidator
// DirectiveDelegate ...
DirectiveDelegate
// DirectiveRedelegate ...
DirectiveRedelegate
// DirectiveUndelegate ...
DirectiveUndelegate
// DirectiveCollectRewards ...
@ -35,7 +32,6 @@ var (
DirectiveCreateValidator: "CreateValidator",
DirectiveEditValidator: "EditValidator",
DirectiveDelegate: "Delegate",
DirectiveRedelegate: "Redelegate",
DirectiveUndelegate: "Undelegate",
DirectiveCollectRewards: "CollectRewards",
}
@ -52,7 +48,7 @@ func (d Directive) String() string {
// CreateValidator - type for creating a new validator
type CreateValidator struct {
Description `json:"description" yaml:"description"`
Description *Description `json:"description" yaml:"description"`
CommissionRates `json:"commission" yaml:"commission"`
MinSelfDelegation *big.Int `json:"min_self_delegation" yaml:"min_self_delegation"`
MaxTotalDelegation *big.Int `json:"max_total_delegation" yaml:"max_total_delegation"`

@ -153,31 +153,43 @@ func (tx *StakingTransaction) Nonce() uint64 {
return tx.data.AccountNonce
}
// StakingMsgToBytes returns the bytes of staking message
func (tx *StakingTransaction) StakingMsgToBytes() (by []byte, err error) {
stakeType := tx.StakingType()
switch stakeType {
case DirectiveCreateValidator:
createValidator := tx.StakingMessage().(CreateValidator)
by, err = rlp.EncodeToBytes(createValidator)
case DirectiveEditValidator:
editValidator := tx.StakingMessage().(EditValidator)
by, err = rlp.EncodeToBytes(editValidator)
case DirectiveDelegate:
delegate := tx.StakingMessage().(Delegate)
by, err = rlp.EncodeToBytes(delegate)
case DirectiveUndelegate:
undelegate := tx.StakingMessage().(Undelegate)
by, err = rlp.EncodeToBytes(undelegate)
case DirectiveCollectRewards:
collectRewards := tx.StakingMessage().(CollectRewards)
by, err = rlp.EncodeToBytes(collectRewards)
// RLPEncodeStakeMsg ..
func (tx *StakingTransaction) RLPEncodeStakeMsg() (by []byte, err error) {
return rlp.EncodeToBytes(tx.data.StakeMsg)
}
// RLPDecodeStakeMsg ..
func RLPDecodeStakeMsg(payload []byte, d Directive) (interface{}, error) {
var oops error
var ds interface{}
switch _, ok := directiveNames[d]; ok {
case false:
return nil, ErrInvalidStakingKind
default:
by = []byte{}
err = ErrInvalidStakingKind
switch d {
case DirectiveCreateValidator:
ds = &CreateValidator{}
case DirectiveEditValidator:
ds = &EditValidator{}
case DirectiveDelegate:
ds = &Delegate{}
case DirectiveUndelegate:
ds = &Undelegate{}
case DirectiveCollectRewards:
ds = &CollectRewards{}
default:
return nil, nil
}
}
return
oops = rlp.DecodeBytes(payload, ds)
if oops != nil {
return nil, oops
}
return ds, nil
}
// StakingType returns the type of staking transaction
@ -192,8 +204,7 @@ func (tx *StakingTransaction) StakingMessage() interface{} {
// SenderAddress returns the address of staking transaction sender
func (tx *StakingTransaction) SenderAddress() (common.Address, error) {
signer := NewEIP155Signer(tx.ChainID())
addr, err := Sender(signer, tx)
addr, err := Sender(NewEIP155Signer(tx.ChainID()), tx)
if err != nil {
return common.Address{}, err
}

@ -1,14 +1,15 @@
package types
import (
"errors"
"math/big"
"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/internal/ctxerror"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
)
// Define validator staking related const
@ -20,10 +21,16 @@ const (
MaxDetailsLength = 280
)
var (
errAddressNotMatch = errors.New("Validator key not match")
)
// ValidatorWrapper contains validator and its delegation information
type ValidatorWrapper struct {
Validator `json:"validator" yaml:"validator"`
Delegations []Delegation `json:"delegations" yaml:"delegations"`
Validator `json:"validator" yaml:"validator"`
Delegations []Delegation `json:"delegations" yaml:"delegations"`
SnapshotValidator *Validator `json:"snapshot_validator" yaml:"snaphost_validator"`
SnapshotDelegations []Delegation `json:"snapshot_delegations" yaml:"snapshot_delegations"`
}
// Validator - data fields for a validator
@ -31,7 +38,7 @@ type Validator struct {
// 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"`
SlotPubKeys []shard.BlsPublicKey `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
@ -80,7 +87,7 @@ func NewDescription(name, identity, website, securityContact, details string) De
// UpdateDescription updates the fields of a given description. An error is
// returned if the resulting description contains an invalid length.
func (d Description) UpdateDescription(d2 Description) (Description, error) {
func UpdateDescription(d2 *Description) (Description, error) {
return NewDescription(
d2.Name,
d2.Identity,
@ -125,3 +132,40 @@ func (v *Validator) GetCommissionRate() numeric.Dec { return v.Commission.Rate }
// GetMinSelfDelegation returns the minimum amount the validator must stake
func (v *Validator) GetMinSelfDelegation() *big.Int { return v.MinSelfDelegation }
// CreateValidatorFromNewMsg creates validator from NewValidator message
func CreateValidatorFromNewMsg(val *CreateValidator) (*Validator, error) {
desc, err := UpdateDescription(val.Description)
if err != nil {
return nil, err
}
commission := Commission{val.CommissionRates, new(big.Int)}
pubKeys := []shard.BlsPublicKey{}
pubKeys = append(pubKeys, val.SlotPubKeys...)
v := Validator{val.ValidatorAddress, pubKeys,
val.Amount, new(big.Int), val.MinSelfDelegation, false,
commission, desc}
return &v, nil
}
// UpdateValidatorFromEditMsg updates validator from EditValidator message
func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator) error {
if validator.Address != edit.ValidatorAddress {
return errAddressNotMatch
}
desc, err := UpdateDescription(edit.Description)
if err != nil {
return err
}
validator.Description = desc
if edit.CommissionRate != nil {
validator.Rate = *edit.CommissionRate
}
if edit.MinSelfDelegation != nil {
validator.MinSelfDelegation = edit.MinSelfDelegation
}
return nil
}

@ -4,8 +4,6 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/numeric"
)
@ -13,7 +11,7 @@ func CreateNewValidator() Validator {
cr := CommissionRates{Rate: numeric.OneDec(), MaxRate: numeric.OneDec(), MaxChangeRate: numeric.ZeroDec()}
c := Commission{cr, big.NewInt(300)}
d := Description{Name: "SuperHero", Identity: "YouWillNotKnow", Website: "under_construction", Details: "N/A"}
v := Validator{Address: common.Address{}, ValidatingPubKey: *bls.RandPrivateKey().GetPublicKey(),
v := Validator{Address: common.Address{}, SlotPubKeys: nil,
Stake: big.NewInt(500), UnbondingHeight: big.NewInt(20), MinSelfDelegation: big.NewInt(7),
Active: false, Commission: c, Description: d}
return v

@ -125,12 +125,12 @@ func fundFaucetContract(chain *core.BlockChain) {
amount := 720000
tx, _ := types.SignTx(types.NewTransaction(nonce+uint64(4), StakingAddress, 0, big.NewInt(int64(amount)), params.TxGas, nil, nil), types.HomesteadSigner{}, FaucetPriKey)
txs = append(txs, tx)
err := contractworker.CommitTransactions(txs, testUserAddress)
err := contractworker.CommitTransactions(txs, nil, testUserAddress)
if err != nil {
fmt.Println(err)
}
block, _ := contractworker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
_, err = chain.InsertChain(types.Blocks{block})
_, err = chain.InsertChain(types.Blocks{block}, true /* verifyHeaders */)
if err != nil {
fmt.Println(err)
}
@ -163,7 +163,7 @@ func callFaucetContractToFundAnAddress(chain *core.BlockChain) {
callEnc = append(callEnc, paddedAddress...)
callfaucettx, _ := types.SignTx(types.NewTransaction(nonce+uint64(5), faucetContractAddress, 0, big.NewInt(0), params.TxGasContractCreation*10, nil, callEnc), types.HomesteadSigner{}, FaucetPriKey)
err = contractworker.CommitTransactions(types.Transactions{callfaucettx}, testUserAddress)
err = contractworker.CommitTransactions(types.Transactions{callfaucettx}, nil, testUserAddress)
if err != nil {
fmt.Println(err)
}
@ -171,7 +171,7 @@ func callFaucetContractToFundAnAddress(chain *core.BlockChain) {
fmt.Println(err)
}
block, _ := contractworker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
_, err = chain.InsertChain(types.Blocks{block})
_, err = chain.InsertChain(types.Blocks{block}, true /* verifyHeaders */)
if err != nil {
fmt.Println(err)
}
@ -241,13 +241,13 @@ func playStaking(chain *core.BlockChain) {
tx, _ := types.SignTx(types.NewTransaction(0, stakeContractAddress, 0, big.NewInt(int64(stake)), params.TxGas*5, nil, callEncl), types.HomesteadSigner{}, allRandomUserKey[i])
stakingtxns = append(stakingtxns, tx)
}
err = contractworker.CommitTransactions(stakingtxns, common.Address{})
err = contractworker.CommitTransactions(stakingtxns, nil, common.Address{})
if err != nil {
fmt.Println(err)
}
block, _ := contractworker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
_, err = chain.InsertChain(types.Blocks{block})
_, err = chain.InsertChain(types.Blocks{block}, true /* verifyHeaders */)
if err != nil {
fmt.Println(err)
}
@ -299,14 +299,14 @@ func playWithdrawStaking(chain *core.BlockChain) {
withdrawstakingtxns = append(withdrawstakingtxns, tx)
}
err = contractworker.CommitTransactions(withdrawstakingtxns, common.Address{})
err = contractworker.CommitTransactions(withdrawstakingtxns, nil, common.Address{})
if err != nil {
fmt.Println("error:")
fmt.Println(err)
}
block, _ := contractworker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
_, err = chain.InsertChain(types.Blocks{block})
_, err = chain.InsertChain(types.Blocks{block}, true /* verifyHeaders */)
if err != nil {
fmt.Println(err)
}
@ -350,7 +350,7 @@ func main() {
gen.SetShardID(0)
gen.AddTx(pendingTxs[i])
})
if _, err := chain.InsertChain(blocks); err != nil {
if _, err := chain.InsertChain(blocks, true /* verifyHeaders */); err != nil {
log.Fatal(err)
}
}

Loading…
Cancel
Save