This commit is contained in:
denis k 2018-08-24 15:40:42 +10:00
parent 507ef74a91
commit 78d17e64cd
4 changed files with 102 additions and 9 deletions

View file

@ -1,6 +1,8 @@
package lcp package lcp
import ( import (
"errors"
"fmt"
"math/big" "math/big"
"testing" "testing"
@ -14,6 +16,44 @@ import (
//types2 "github.com/pavelkrolevets/go-ethereum/core/types" //types2 "github.com/pavelkrolevets/go-ethereum/core/types"
) )
func (ec *EpochContext) cVotes() (votes map[common.Address]*big.Int, err error) {
votes = map[common.Address]*big.Int{}
delegateTrie := ec.Context.DelegateTrie()
candidateTrie := ec.Context.CandidateTrie()
statedb := ec.statedb
iterCandidate := trie.NewIterator(candidateTrie.NodeIterator(nil))
existCandidate := iterCandidate.Next()
if !existCandidate {
return votes, errors.New("no candidates")
}
for existCandidate {
candidate := iterCandidate.Value
candidateAddr := common.BytesToAddress(candidate)
delegateIterator := trie.NewIterator(delegateTrie.PrefixIterator(candidate))
existDelegator := delegateIterator.Next()
if !existDelegator {
votes[candidateAddr] = new(big.Int)
existCandidate = iterCandidate.Next()
continue
}
for existDelegator {
delegator := delegateIterator.Value
score, ok := votes[candidateAddr]
if !ok {
score = new(big.Int)
}
delegatorAddr := common.BytesToAddress(delegator)
weight := statedb.GetBalance(delegatorAddr)
score.Add(score, weight)
votes[candidateAddr] = score
existDelegator = delegateIterator.Next()
}
existCandidate = iterCandidate.Next()
}
return votes, nil
}
func TestEpochContextCountVotes(t *testing.T) { func TestEpochContextCountVotes(t *testing.T) {
voteMap := map[common.Address][]common.Address{ voteMap := map[common.Address][]common.Address{
common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"): { common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"): {
@ -38,10 +78,12 @@ func TestEpochContextCountVotes(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
epochContext := &EpochContext{ epochContext := &EpochContext{
Context: LCPContext, Context: LCPContext,
statedb: stateDB, statedb: stateDB,
} }
_, err = epochContext.countVotes()
// _, err = epochContext.countVotes()
_, err = epochContext.cVotes()
assert.NotNil(t, err) assert.NotNil(t, err)
for candidate, electors := range voteMap { for candidate, electors := range voteMap {
@ -49,17 +91,30 @@ func TestEpochContextCountVotes(t *testing.T) {
for _, elector := range electors { for _, elector := range electors {
stateDB.SetBalance(elector, big.NewInt(balance)) stateDB.SetBalance(elector, big.NewInt(balance))
assert.Nil(t, LCPContext.Delegate(elector, candidate)) assert.Nil(t, LCPContext.Delegate(elector, candidate))
// print candidates list
_, e := epochContext.Context.VoteTrie().TryGet([]byte(elector.Bytes()))
if _, ok := e.(*trie.MissingNodeError); !ok {
fmt.Println(err)
}
} }
} }
result, err := epochContext.countVotes() result, err := epochContext.countVotes()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, len(voteMap), len(result)) assert.Equal(t, len(voteMap), len(result))
for candidate, electors := range voteMap { for candidate, electors := range voteMap {
voteCount, ok := result[candidate] voteCount, ok := result[candidate]
assert.True(t, ok) assert.True(t, ok)
fmt.Println("voteCount =", voteCount)
fmt.Println("ele =", balance*int64(len(electors)))
assert.Equal(t, balance*int64(len(electors)), voteCount.Int64()) assert.Equal(t, balance*int64(len(electors)), voteCount.Int64())
} }
} }
// //
//func TestLookupValidator(t *testing.T) { //func TestLookupValidator(t *testing.T) {
// db, _ := ethdb.NewMemDatabase() // db, _ := ethdb.NewMemDatabase()

View file

@ -356,7 +356,7 @@ func AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header
} }
func (d *LCP) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, func (d *LCP) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt, LCPContext *types.LCPContext) (*types.Block, error) { uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
// Accumulate block rewards and commit the final state root // Accumulate block rewards and commit the final state root
AccumulateRewards(chain.Config(), state, header, uncles) AccumulateRewards(chain.Config(), state, header, uncles)
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))

View file

@ -17,6 +17,8 @@
package core package core
import ( import (
"math/big"
"github.com/pavelkrolevets/go-ethereum/common" "github.com/pavelkrolevets/go-ethereum/common"
"github.com/pavelkrolevets/go-ethereum/consensus" "github.com/pavelkrolevets/go-ethereum/consensus"
"github.com/pavelkrolevets/go-ethereum/consensus/misc" "github.com/pavelkrolevets/go-ethereum/consensus/misc"
@ -65,10 +67,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
// Set out block dpos context
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) receipt, _, err := ApplyTransaction(p.config, block.LCPCtx(), p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -85,11 +88,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// and uses the input parameters for its environment. It returns the receipt // and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { func ApplyTransaction(config *params.ChainConfig, lcpContext *types.LCPContext, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
if msg.To() == nil && msg.Type() != types.Binary {
return nil, 0, types.ErrInvalidType
}
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
context := NewEVMContext(msg, header, bc, author) context := NewEVMContext(msg, header, bc, author)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
@ -100,6 +107,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
if msg.Type() != types.Binary {
if err = applyLcpMessage(lcpContext, msg); err != nil {
return nil, 0, err
}
}
// Update the state with pending changes // Update the state with pending changes
var root []byte var root []byte
if config.IsByzantium(header.Number) { if config.IsByzantium(header.Number) {
@ -107,20 +120,40 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
} else { } else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
} }
*usedGas += gas // *usedGas += gas
usedGas.Add(usedGas, gas)
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
// based on the eip phase, we're passing wether the root touch-delete accounts. // based on the eip phase, we're passing wether the root touch-delete accounts.
receipt := types.NewReceipt(root, failed, *usedGas) // receipt := types.NewReceipt(root, failed, *usedGas)
receipt := types.NewReceipt(root, failed, usedGas)
receipt.TxHash = tx.Hash() receipt.TxHash = tx.Hash()
receipt.GasUsed = gas // receipt.GasUsed = gas
receipt.GasUsed = new(big.Int).Set(gas)
// if the transaction created a contract, store the creation address in the receipt. // if the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil { if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
} }
// Set the receipt logs and create a bloom for filtering // Set the receipt logs and create a bloom for filtering
receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
return receipt, gas, err return receipt, gas, err
} }
func applyLcpMessage(lcpContext *types.LCPContext, msg types.Message) error {
switch msg.Type() {
case types.LoginCandidate:
lcpContext.BecomeCandidate(msg.From())
case types.LogoutCandidate:
lcpContext.KickoutCandidate(msg.From())
case types.Delegate:
lcpContext.Delegate(msg.From(), *(msg.To()))
case types.UnDelegate:
lcpContext.UnDelegate(msg.From(), *(msg.To()))
default:
return types.ErrInvalidType
}
return nil
}

View file

@ -31,6 +31,9 @@ import (
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go //go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
// transaction type
type TxType uint8
var ( var (
ErrInvalidSig = errors.New("invalid transaction v, r, s values") ErrInvalidSig = errors.New("invalid transaction v, r, s values")
) )
@ -387,6 +390,7 @@ type Message struct {
gasPrice *big.Int gasPrice *big.Int
data []byte data []byte
checkNonce bool checkNonce bool
txType TxType
} }
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool) Message { func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool) Message {
@ -410,3 +414,4 @@ func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce } func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data } func (m Message) Data() []byte { return m.data }
func (m Message) CheckNonce() bool { return m.checkNonce } func (m Message) CheckNonce() bool { return m.checkNonce }
func (m Message) Type() TxType { return m.txType }