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

pull/1795/head
chao 5 years ago
commit 12e21e3226
  1. 119
      api/service/syncing/syncing.go
  2. 4
      cmd/client/wallet/main.go
  3. 22
      cmd/staking/root.go
  4. 76
      core/blockchain.go
  5. 27
      core/core_test.go
  6. 3
      core/state_processor.go
  7. 33
      hmy/api_backend.go
  8. 2
      hmy/backend.go
  9. 2
      internal/configs/sharding/localnet.go
  10. 2
      internal/configs/sharding/mainnet.go
  11. 51
      internal/configs/sharding/testnet.go
  12. 11
      internal/hmyapi/backend.go
  13. 284
      internal/hmyapi/blockchain.go
  14. 18
      internal/hmyapi/transactionpool.go
  15. 11
      internal/hmyapi/types.go
  16. 6
      internal/params/config.go
  17. 18
      node/node_explorer.go
  18. 2
      node/node_handler.go
  19. 2
      node/service_setup.go
  20. 52
      node/worker/worker.go
  21. 3
      staking/types/messages.go
  22. 76
      staking/types/transaction.go
  23. 10
      test/chain/main.go
  24. 4
      test/deploy.sh

@ -26,14 +26,13 @@ import (
// Constants for syncing.
const (
SleepTimeAfterNonConsensusBlockHashes = time.Second * 30
TimesToFail = 5 // Downloadblocks service retry limit
RegistrationNumber = 3
SyncingPortDifference = 3000
inSyncThreshold = 0 // when peerBlockHeight - myBlockHeight <= inSyncThreshold, it's ready to join consensus
BatchSize uint32 = 1000 //maximum size for one query of block hashes
SyncLoopFrequency = 1 // unit in second
LastMileBlocksSize = 10
TimesToFail = 5 // Downloadblocks service retry limit
RegistrationNumber = 3
SyncingPortDifference = 3000
inSyncThreshold = 0 // when peerBlockHeight - myBlockHeight <= inSyncThreshold, it's ready to join consensus
BatchSize uint32 = 1000 //maximum size for one query of block hashes
SyncLoopFrequency = 1 // unit in second
LastMileBlocksSize = 10
)
// SyncPeerConfig is peer config to sync.
@ -315,8 +314,11 @@ func (sc *SyncConfig) cleanUpPeers(maxFirstID int) {
}
}
// GetBlockHashesConsensusAndCleanUp chesk if all consensus hashes are equal.
func (sc *SyncConfig) GetBlockHashesConsensusAndCleanUp() bool {
// GetBlockHashesConsensusAndCleanUp selects the most common peer config based on their block hashes to download/sync.
// Note that choosing the most common peer config does not guarantee that the blocks to be downloaded are the correct ones.
// The subsequent node syncing steps of verifying the block header chain will give such confirmation later.
// If later block header verification fails with the sync peer config chosen here, the entire sync loop gets retried with a new peer set.
func (sc *SyncConfig) GetBlockHashesConsensusAndCleanUp() {
sc.mtx.Lock()
defer sc.mtx.Unlock()
// Sort all peers by the blockHashes.
@ -328,55 +330,39 @@ func (sc *SyncConfig) GetBlockHashesConsensusAndCleanUp() bool {
Int("maxFirstID", maxFirstID).
Int("maxCount", maxCount).
Msg("[SYNC] block consensus hashes")
if float64(maxCount) >= core.ShardingSchedule.ConsensusRatio()*float64(len(sc.peers)) {
sc.cleanUpPeers(maxFirstID)
return true
}
return false
sc.cleanUpPeers(maxFirstID)
}
// GetConsensusHashes gets all hashes needed to download.
func (ss *StateSync) GetConsensusHashes(startHash []byte, size uint32) bool {
count := 0
for {
var wg sync.WaitGroup
ss.syncConfig.ForEachPeer(func(peerConfig *SyncPeerConfig) (brk bool) {
wg.Add(1)
go func() {
defer wg.Done()
response := peerConfig.client.GetBlockHashes(startHash, size, ss.selfip, ss.selfport)
if response == nil {
utils.Logger().Warn().
Str("peerIP", peerConfig.ip).
Str("peerPort", peerConfig.port).
Msg("[SYNC] GetConsensusHashes Nil Response")
return
}
if len(response.Payload) > int(size+1) {
utils.Logger().Warn().
Uint32("requestSize", size).
Int("respondSize", len(response.Payload)).
Msg("[SYNC] GetConsensusHashes: receive more blockHahses than request!")
peerConfig.blockHashes = response.Payload[:size+1]
} else {
peerConfig.blockHashes = response.Payload
}
}()
return
})
wg.Wait()
if ss.syncConfig.GetBlockHashesConsensusAndCleanUp() {
break
}
if count > TimesToFail {
utils.Logger().Info().Msg("[SYNC] GetConsensusHashes: reached retry limit")
return false
}
count++
time.Sleep(SleepTimeAfterNonConsensusBlockHashes)
}
func (ss *StateSync) GetConsensusHashes(startHash []byte, size uint32) {
var wg sync.WaitGroup
ss.syncConfig.ForEachPeer(func(peerConfig *SyncPeerConfig) (brk bool) {
wg.Add(1)
go func() {
defer wg.Done()
response := peerConfig.client.GetBlockHashes(startHash, size, ss.selfip, ss.selfport)
if response == nil {
utils.Logger().Warn().
Str("peerIP", peerConfig.ip).
Str("peerPort", peerConfig.port).
Msg("[SYNC] GetConsensusHashes Nil Response")
return
}
if len(response.Payload) > int(size+1) {
utils.Logger().Warn().
Uint32("requestSize", size).
Int("respondSize", len(response.Payload)).
Msg("[SYNC] GetConsensusHashes: receive more blockHahses than request!")
peerConfig.blockHashes = response.Payload[:size+1]
} else {
peerConfig.blockHashes = response.Payload
}
}()
return
})
wg.Wait()
ss.syncConfig.GetBlockHashesConsensusAndCleanUp()
utils.Logger().Info().Msg("[SYNC] Finished getting consensus block hashes")
return true
}
func (ss *StateSync) generateStateSyncTaskQueue(bc *core.BlockChain) {
@ -388,13 +374,13 @@ func (ss *StateSync) generateStateSyncTaskQueue(bc *core.BlockChain) {
Err(err).
Int("taskIndex", id).
Str("taskBlock", hex.EncodeToString(blockHash)).
Msg("cannot add task")
Msg("[SYNC] generateStateSyncTaskQueue: cannot add task")
}
}
brk = true
return
})
utils.Logger().Info().Int64("length", ss.stateSyncTaskQueue.Len()).Msg("[SYNC] Finished generateStateSyncTaskQueue")
utils.Logger().Info().Int64("length", ss.stateSyncTaskQueue.Len()).Msg("[SYNC] generateStateSyncTaskQueue: finished")
}
// downloadBlocks downloads blocks from state sync task queue.
@ -409,7 +395,7 @@ func (ss *StateSync) downloadBlocks(bc *core.BlockChain) {
for !stateSyncTaskQueue.Empty() {
task, err := ss.stateSyncTaskQueue.Poll(1, time.Millisecond)
if err == queue.ErrTimeout || len(task) == 0 {
utils.Logger().Error().Err(err).Msg("[SYNC] ss.stateSyncTaskQueue poll timeout")
utils.Logger().Error().Err(err).Msg("[SYNC] downloadBlocks: ss.stateSyncTaskQueue poll timeout")
break
}
syncTask := task[0].(SyncBlockTask)
@ -417,7 +403,7 @@ func (ss *StateSync) downloadBlocks(bc *core.BlockChain) {
payload, err := peerConfig.GetBlocks([][]byte{syncTask.blockHash})
if err != nil || len(payload) == 0 {
count++
utils.Logger().Error().Err(err).Int("failNumber", count).Msg("[SYNC] GetBlocks failed")
utils.Logger().Error().Err(err).Int("failNumber", count).Msg("[SYNC] downloadBlocks: GetBlocks failed")
if count > TimesToFail {
break
}
@ -426,7 +412,7 @@ func (ss *StateSync) downloadBlocks(bc *core.BlockChain) {
Err(err).
Int("taskIndex", syncTask.index).
Str("taskBlock", hex.EncodeToString(syncTask.blockHash)).
Msg("cannot add task")
Msg("downloadBlocks: cannot add task")
}
continue
}
@ -458,7 +444,7 @@ func (ss *StateSync) downloadBlocks(bc *core.BlockChain) {
return
})
wg.Wait()
utils.Logger().Info().Msg("[SYNC] Finished downloadBlocks")
utils.Logger().Info().Msg("[SYNC] downloadBlocks: finished")
}
// CompareBlockByHash compares two block by hash, it will be used in sort the blocks
@ -545,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
@ -560,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())
@ -607,8 +592,7 @@ func (ss *StateSync) generateNewState(bc *core.BlockChain, worker *worker.Worker
}
parentHash = block.Hash()
}
// TODO ek – Do we need to hold syncMux now that syncConfig has its onw
// mutex?
// TODO ek – Do we need to hold syncMux now that syncConfig has its own mutex?
ss.syncMux.Lock()
ss.syncConfig.ForEachPeer(func(peer *SyncPeerConfig) (brk bool) {
peer.newBlocks = []*types.Block{}
@ -635,10 +619,7 @@ func (ss *StateSync) generateNewState(bc *core.BlockChain, worker *worker.Worker
// TODO: return error
func (ss *StateSync) ProcessStateSync(startHash []byte, size uint32, bc *core.BlockChain, worker *worker.Worker) {
// Gets consensus hashes.
if !ss.GetConsensusHashes(startHash, size) {
utils.Logger().Debug().Msg("[SYNC] ProcessStateSync unable to reach consensus on ss.GetConsensusHashes")
return
}
ss.GetConsensusHashes(startHash, size)
ss.generateStateSyncTaskQueue(bc)
// Download blocks.
if ss.stateSyncTaskQueue.Len() > 0 {

@ -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)

@ -78,11 +78,11 @@ func (s *staker) run(cmd *cobra.Command, args []string) error {
SlotPubKeys: []shard.BlsPublicKey{pub},
Amount: big.NewInt(100),
}
// return staking.DirectiveDelegate, staking.Delegate{
// common.Address(dAddr),
// common.Address(dAddr),
// big.NewInt(10),
// }
// return staking.DirectiveDelegate, staking.Delegate{
// common.Address(dAddr),
// common.Address(dAddr),
// big.NewInt(10),
// }
}
stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker)
@ -101,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}

@ -41,9 +41,11 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
internal_common "github.com/harmony-one/harmony/internal/common"
"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/numeric"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
lru "github.com/hashicorp/golang-lru"
@ -814,7 +816,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 +1142,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 +1192,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 +1207,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 +1229,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 +1260,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 +1320,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
@ -2335,25 +2347,49 @@ func (bc *BlockChain) UpdateValidatorMap(tx *staking.StakingTransaction) error {
// CurrentValidatorAddresses returns the address of active validators for current epoch
func (bc *BlockChain) CurrentValidatorAddresses() []common.Address {
return nil
return make([]common.Address, 0)
}
// ValidatorCandidates returns the up to date validator candidates for next epoch
func (bc *BlockChain) ValidatorCandidates() []common.Address {
return nil
return make([]common.Address, 0)
}
// ValidatorInformation returns the information of validator
func (bc *BlockChain) ValidatorInformation(addr common.Address) *staking.Validator {
return nil
commission := staking.Commission{
UpdateHeight: big.NewInt(0),
}
commission.CommissionRates = staking.CommissionRates{
Rate: numeric.Dec{Int: big.NewInt(0)},
MaxRate: numeric.Dec{Int: big.NewInt(0)},
MaxChangeRate: numeric.Dec{Int: big.NewInt(0)},
}
validator := &staking.Validator{
Address: internal_common.ParseAddr("0x0000000000000000000000000000000000000000000000000000000000000000"),
SlotPubKeys: make([]shard.BlsPublicKey, 0),
Stake: big.NewInt(0),
UnbondingHeight: big.NewInt(0),
MinSelfDelegation: big.NewInt(0),
Active: false,
}
validator.Commission = commission
validator.Description = staking.Description{
Name: "lol",
Identity: "lol",
Website: "lol",
SecurityContact: "lol",
Details: "lol",
}
return validator
}
// DelegatorsInformation returns up to date information of delegators of a given validator address
func (bc *BlockChain) DelegatorsInformation(addr common.Address) []*staking.Delegation {
return nil
return make([]*staking.Delegation, 0)
}
// ValidatorStakingWithDelegation returns the amount of staking after applying all delegated stakes
func (bc *BlockChain) ValidatorStakingWithDelegation(addr common.Address) *big.Int {
return nil
return big.NewInt(0)
}

@ -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,
},
}

@ -249,7 +249,7 @@ func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *bloc
// 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.StakingMsgToBytes()
payload, err := tx.RLPEncodeStakeMsg()
if err != nil {
return types.Message{}, err
}
@ -257,6 +257,7 @@ func StakingToMessage(tx *staking.StakingTransaction, blockNum *big.Int) (types.
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 {

@ -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,21 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
return &PublicBlockChainAPI{b}
}
// 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 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) {
block, err := s.b.BlockByNumber(ctx, blockNr)
if block != nil {
response, err := RPCMarshalBlock(block, true, fullTx)
blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: 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"} {
@ -58,14 +70,84 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.GetBlock(ctx, blockHash)
if block != nil {
return RPCMarshalBlock(block, true, fullTx)
blockArgs := BlockArgs{WithSigners: false, InclTx: true, FullTx: 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))
// GetBlockByNumberNew 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) GetBlockByNumberNew(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, blockArgs)
if err == nil && blockNr == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil
}
}
return response, err
}
return nil, err
}
// GetBlockByHashNew returns the requested block. 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) GetBlockByHashNew(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, blockArgs)
}
return nil, err
}
// 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 +175,191 @@ 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 || uint64(blockNr) >= uint64(s.BlockNumber()) {
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) {
if uint64(blockNr) == 0 || uint64(blockNr) >= uint64(s.BlockNumber()) {
return false, nil
}
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 {
totalSigned := uint64(0)
lastBlock := uint64(0)
blockHeight := uint64(s.BlockNumber())
if blockHeight >= defaultBlocksPeriod {
lastBlock = blockHeight - defaultBlocksPeriod + 1
}
for i := lastBlock; i <= blockHeight; 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))
slotPubKeys := make([]string, 0)
for _, slotPubKey := range validator.SlotPubKeys {
slotPubKeys = append(slotPubKeys, slotPubKey.Hex())
}
fields := map[string]interface{}{
"address": validator.Address.String(),
"stake": hexutil.Uint64(validator.Stake.Uint64()),
"name": validator.Description.Name,
"slotPubKeys": 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),
}

@ -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).

@ -58,7 +58,7 @@ func (node *Node) setupForNewNode() {
func (node *Node) setupForClientNode() {
// Register networkinfo service. "0" is the beacon shard ID
node.serviceManager.RegisterService(service.NetworkInfo, networkinfo.MustNew(node.host, nodeconfig.NewGroupIDByShardID(0), nil, nil, node.networkInfoDHTPath()))
node.serviceManager.RegisterService(service.NetworkInfo, networkinfo.MustNew(node.host, nodeconfig.NewGroupIDByShardID(0), nil, nil, ""))
}
func (node *Node) setupForExplorerNode() {

@ -62,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")
@ -108,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:
@ -117,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]++
}
}
}
}
@ -140,7 +151,7 @@ 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
}
@ -155,10 +166,11 @@ func (w *Worker) SelectStakingTransactionsForNewBlock(
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())
}
//if w.current.gasPool == nil {
// w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit())
//}
selected := staking.StakingTransactions{}
// TODO: chao add total gas fee checking when needed
@ -424,8 +436,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()

@ -21,8 +21,6 @@ const (
DirectiveEditValidator
// DirectiveDelegate ...
DirectiveDelegate
// DirectiveRedelegate ...
DirectiveRedelegate
// DirectiveUndelegate ...
DirectiveUndelegate
// DirectiveCollectRewards ...
@ -34,7 +32,6 @@ var (
DirectiveCreateValidator: "CreateValidator",
DirectiveEditValidator: "EditValidator",
DirectiveDelegate: "Delegate",
DirectiveRedelegate: "Redelegate",
DirectiveUndelegate: "Undelegate",
DirectiveCollectRewards: "CollectRewards",
}

@ -157,46 +157,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, ok := tx.StakingMessage().(CreateValidator)
if !ok {
return nil, errStakingTransactionTypeCastErr
}
by, err = rlp.EncodeToBytes(createValidator)
case DirectiveEditValidator:
editValidator, ok := tx.StakingMessage().(EditValidator)
if !ok {
return nil, errStakingTransactionTypeCastErr
}
by, err = rlp.EncodeToBytes(editValidator)
case DirectiveDelegate:
delegate, ok := tx.StakingMessage().(Delegate)
if !ok {
return nil, errStakingTransactionTypeCastErr
}
by, err = rlp.EncodeToBytes(delegate)
case DirectiveUndelegate:
undelegate, ok := tx.StakingMessage().(Undelegate)
if !ok {
return nil, errStakingTransactionTypeCastErr
}
by, err = rlp.EncodeToBytes(undelegate)
case DirectiveCollectRewards:
collectRewards, ok := tx.StakingMessage().(CollectRewards)
if !ok {
return nil, errStakingTransactionTypeCastErr
}
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
}
}
oops = rlp.DecodeBytes(payload, ds)
if oops != nil {
return nil, oops
}
return
return ds, nil
}
// StakingType returns the type of staking transaction
@ -211,8 +208,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
}

@ -130,7 +130,7 @@ func fundFaucetContract(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)
}
@ -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)
}
@ -247,7 +247,7 @@ func playStaking(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)
}
@ -306,7 +306,7 @@ func playWithdrawStaking(chain *core.BlockChain) {
}
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)
}
}

@ -142,9 +142,7 @@ cleanup
# Also it's recommended to use `go build` for testing the whole exe.
if [ "${NOBUILD}" != "true" ]; then
pushd $ROOT
scripts/go_executable_build.sh harmony
scripts/go_executable_build.sh wallet
scripts/go_executable_build.sh bootnode
scripts/go_executable_build.sh
popd
fi

Loading…
Cancel
Save