This commit is contained in:
denis k 2018-08-24 15:48:25 +10:00
commit 838cb4d5bd
14 changed files with 528 additions and 438 deletions

View file

@ -167,6 +167,8 @@ func BytesToAddress(b []byte) Address {
return a return a
} }
func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) }
// BigToAddress returns Address with byte values of b. // BigToAddress returns Address with byte values of b.
// If b is larger than len(h), b will be cropped from the left. // If b is larger than len(h), b will be cropped from the left.
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
@ -219,7 +221,7 @@ func (a Address) Hex() string {
func (a Address) String() string { func (a Address) String() string {
return a.Hex() return a.Hex()
} }
func (a Address) Str() string { return string(a[:]) }
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is, // Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
// without going through the stringer interface used for logging. // without going through the stringer interface used for logging.
func (a Address) Format(s fmt.State, c rune) { func (a Address) Format(s fmt.State, c rune) {

View file

@ -21,7 +21,6 @@ import (
"github.com/pavelkrolevets/go-ethereum/consensus" "github.com/pavelkrolevets/go-ethereum/consensus"
"github.com/pavelkrolevets/go-ethereum/core/types" "github.com/pavelkrolevets/go-ethereum/core/types"
"github.com/pavelkrolevets/go-ethereum/rpc" "github.com/pavelkrolevets/go-ethereum/rpc"
"github.com/pavelkrolevets/go-ethereum/trie"
"math/big" "math/big"
) )
@ -44,7 +43,7 @@ func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error)
return nil, errUnknownBlock return nil, errUnknownBlock
} }
epochTrie, err := types.NewEpochTrie(header.LCPContext.EpochHash, trie.NewDatabase(api.lcp.db)) epochTrie, err := types.NewEpochTrie(header.LCPContext.EpochHash, api.lcp.db)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -10,50 +10,14 @@ import (
"github.com/pavelkrolevets/go-ethereum/core/state" "github.com/pavelkrolevets/go-ethereum/core/state"
"github.com/pavelkrolevets/go-ethereum/core/types" "github.com/pavelkrolevets/go-ethereum/core/types"
"github.com/pavelkrolevets/go-ethereum/ethdb" "github.com/pavelkrolevets/go-ethereum/ethdb"
"github.com/pavelkrolevets/go-ethereum/trie"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
//types2 "github.com/pavelkrolevets/go-ethereum/core/types"
"fmt"
"github.com/pavelkrolevets/go-ethereum/trie"
"strconv"
"strings"
) )
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"): {
@ -72,9 +36,9 @@ func TestEpochContextCountVotes(t *testing.T) {
} }
balance := int64(5) balance := int64(5)
db := ethdb.NewMemDatabase() db := ethdb.NewMemDatabase()
bdb := trie.NewDatabase(db) //dbd := trie.NewDatabase(db)
stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
LCPContext, err := types.NewLCPContext(bdb) LCPContext, err := types.NewLCPContext(db)
assert.Nil(t, err) assert.Nil(t, err)
epochContext := &EpochContext{ epochContext := &EpochContext{
@ -88,19 +52,21 @@ func TestEpochContextCountVotes(t *testing.T) {
for candidate, electors := range voteMap { for candidate, electors := range voteMap {
assert.Nil(t, LCPContext.BecomeCandidate(candidate)) assert.Nil(t, LCPContext.BecomeCandidate(candidate))
//for _, delegate := range electors{
// assert.Nil(t, LCPContext.BecomeDelegate(delegate))
// fmt.Println(delegate)
//}
//fmt.Println(electors)
for _, elector := range electors { for _, elector := range electors {
stateDB.SetBalance(elector, big.NewInt(balance)) epochContext.statedb.SetBalance(elector, big.NewInt(balance))
//bal := epochContext.statedb.GetBalance(elector)
//fmt.Println(bal)
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()
//fmt.Println(result)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, len(voteMap), len(result)) assert.Equal(t, len(voteMap), len(result))
@ -115,300 +81,315 @@ func TestEpochContextCountVotes(t *testing.T) {
} }
} }
// func TestLookupValidator(t *testing.T) {
//func TestLookupValidator(t *testing.T) { db := ethdb.NewMemDatabase()
// db, _ := ethdb.NewMemDatabase() dposCtx, _ := types.NewLCPContext(db)
// dposCtx, _ := types.NewDposContext(db) mockEpochContext := &EpochContext{
// mockEpochContext := &EpochContext{ Context: dposCtx,
// DposContext: dposCtx, }
// } validators := []common.Address{
// validators := []common.Address{ common.StringToAddress("addr1"),
// common.StringToAddress("addr1"), common.StringToAddress("addr2"),
// common.StringToAddress("addr2"), common.StringToAddress("addr3"),
// common.StringToAddress("addr3"), }
// } mockEpochContext.Context.SetPeriodBlock(1)
// mockEpochContext.DposContext.SetValidators(validators) mockEpochContext.Context.SetEpochInterval(86400)
// for i, expected := range validators { mockEpochContext.Context.SetMaxValidators(3)
// got, _ := mockEpochContext.lookupValidator(int64(i) * blockInterval) blockInterval := mockEpochContext.Context.GetPeriodBlock()
// if got != expected { maxval := mockEpochContext.Context.GetMaxValidators()
// t.Errorf("Failed to test lookup validator, %s was expected but got %s", expected.Str(), got.Str()) epoch_int := mockEpochContext.Context.GetEpochInterval()
// }
// } fmt.Println(blockInterval, maxval, epoch_int)
// _, err := mockEpochContext.lookupValidator(blockInterval - 1) mockEpochContext.Context.SetValidators(validators)
// if err != ErrInvalidMintBlockTime { for i, expected := range validators {
// t.Errorf("Failed to test lookup validator. err '%v' was expected but got '%v'", ErrInvalidMintBlockTime, err) fmt.Println(i, expected)
// } got, _ := mockEpochContext.lookupValidator(int64(i) * blockInterval)
//} if got != expected {
// t.Errorf("Failed to test lookup validator, %s was expected but got %s", expected.Str(), got.Str())
//func TestEpochContextKickoutValidator(t *testing.T) { }
// db, _ := ethdb.NewMemDatabase() }
// stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) _, err := mockEpochContext.lookupValidator(blockInterval - 1)
// dposContext, err := types.NewDposContext(db) if err != ErrInvalidMintBlockTime {
// assert.Nil(t, err) t.Errorf("Failed to test lookup validator. err '%v' was expected but got '%v'", ErrInvalidMintBlockTime, err)
// epochContext := &EpochContext{ }
// TimeStamp: epochInterval, }
// DposContext: dposContext,
// statedb: stateDB, func TestEpochContextKickoutValidator(t *testing.T) {
// } db := ethdb.NewMemDatabase()
// atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2 stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
// testEpoch := int64(1) dposContext, err := types.NewLCPContext(db)
// assert.Nil(t, err)
// // no validator can be kickout, because all validators mint enough block at least
// validators := []common.Address{} epochContext := &EpochContext{
// for i := 0; i < maxValidatorSize; i++ { TimeStamp: epochInterval,
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) Context: dposContext,
// validators = append(validators, validator) statedb: stateDB,
// assert.Nil(t, dposContext.BecomeCandidate(validator)) }
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt) epochContext.Context.SetPeriodBlock(1)
// } epochContext.Context.SetEpochInterval(86400)
// assert.Nil(t, dposContext.SetValidators(validators)) epochContext.Context.SetMaxValidators(3)
// assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) maxValidatorSize := int(epochContext.Context.GetMaxValidators())
// candidateMap := getCandidates(dposContext.CandidateTrie()) atLeastMintCnt := epochInterval / blockInterval / int64(maxValidatorSize) / 2
// assert.Equal(t, maxValidatorSize +1, len(candidateMap)) testEpoch := int64(1)
//
// // atLeast a safeSize count candidate will reserve // no validator can be kickout, because all validators mint enough block at least
// dposContext, err = types.NewDposContext(db) validators := []common.Address{}
// assert.Nil(t, err) for i := 0; i < int(maxValidatorSize); i++ {
// epochContext = &EpochContext{ validator := common.StringToAddress("addr" + strconv.Itoa(i))
// TimeStamp: epochInterval, validators = append(validators, validator)
// DposContext: dposContext, assert.Nil(t, dposContext.BecomeCandidate(validator))
// statedb: stateDB, setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
// } }
// validators = []common.Address{} assert.Nil(t, dposContext.SetValidators(validators))
// for i := 0; i < maxValidatorSize; i++ { assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// validators = append(validators, validator) candidateMap := getCandidates(dposContext.CandidateTrie())
// assert.Nil(t, dposContext.BecomeCandidate(validator)) assert.Equal(t, maxValidatorSize+1, len(candidateMap))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-int64(i)-1)
// } // atLeast a safeSize count candidate will reserve
// assert.Nil(t, dposContext.SetValidators(validators)) dposContext, err = types.NewLCPContext(db)
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) assert.Nil(t, err)
// candidateMap = getCandidates(dposContext.CandidateTrie()) epochContext = &EpochContext{
// assert.Equal(t, safeSize, len(candidateMap)) TimeStamp: epochInterval,
// for i := maxValidatorSize - 1; i >= safeSize; i-- { Context: dposContext,
// assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(i))]) statedb: stateDB,
// } }
// validators = []common.Address{}
// // all validator will be kickout, because all validators didn't mint enough block at least for i := 0; i < int(maxValidatorSize); i++ {
// dposContext, err = types.NewDposContext(db) validator := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.Nil(t, err) validators = append(validators, validator)
// epochContext = &EpochContext{ assert.Nil(t, dposContext.BecomeCandidate(validator))
// TimeStamp: epochInterval, setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-int64(i)-1)
// DposContext: dposContext, }
// statedb: stateDB, assert.Nil(t, dposContext.SetValidators(validators))
// } assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// validators = []common.Address{} candidateMap = getCandidates(dposContext.CandidateTrie())
// for i := 0; i < maxValidatorSize; i++ { assert.Equal(t, safeSize, len(candidateMap))
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) for i := int(maxValidatorSize) - 1; i >= safeSize; i-- {
// validators = append(validators, validator) assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(i))])
// assert.Nil(t, dposContext.BecomeCandidate(validator)) }
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// } // all validator will be kickout, because all validators didn't mint enough block at least
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ { dposContext, err = types.NewLCPContext(db)
// candidate := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, err)
// assert.Nil(t, dposContext.BecomeCandidate(candidate)) epochContext = &EpochContext{
// } TimeStamp: epochInterval,
// assert.Nil(t, dposContext.SetValidators(validators)) Context: dposContext,
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) statedb: stateDB,
// candidateMap = getCandidates(dposContext.CandidateTrie()) }
// assert.Equal(t, maxValidatorSize, len(candidateMap)) validators = []common.Address{}
// for i := 0; i < int(maxValidatorSize); i++ {
// // only one validator mint count is not enough validator := common.StringToAddress("addr" + strconv.Itoa(i))
// dposContext, err = types.NewDposContext(db) validators = append(validators, validator)
// assert.Nil(t, err) assert.Nil(t, dposContext.BecomeCandidate(validator))
// epochContext = &EpochContext{ setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// TimeStamp: epochInterval, }
// DposContext: dposContext, for i := int(maxValidatorSize); i < int(maxValidatorSize)*2; i++ {
// statedb: stateDB, candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// } assert.Nil(t, dposContext.BecomeCandidate(candidate))
// validators = []common.Address{} }
// for i := 0; i < maxValidatorSize; i++ { assert.Nil(t, dposContext.SetValidators(validators))
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// validators = append(validators, validator) candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Nil(t, dposContext.BecomeCandidate(validator)) assert.Equal(t, maxValidatorSize, len(candidateMap))
// if i == 0 {
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1) // only one validator mint count is not enough
// } else { dposContext, err = types.NewLCPContext(db)
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt) assert.Nil(t, err)
// } epochContext = &EpochContext{
// } TimeStamp: epochInterval,
// assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr"))) Context: dposContext,
// assert.Nil(t, dposContext.SetValidators(validators)) statedb: stateDB,
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) }
// candidateMap = getCandidates(dposContext.CandidateTrie()) validators = []common.Address{}
// assert.Equal(t, maxValidatorSize, len(candidateMap)) for i := 0; i < int(maxValidatorSize); i++ {
// assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(0))]) validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// // epochTime is not complete, all validators mint enough block at least assert.Nil(t, dposContext.BecomeCandidate(validator))
// dposContext, err = types.NewDposContext(db) if i == 0 {
// assert.Nil(t, err) setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// epochContext = &EpochContext{ } else {
// TimeStamp: epochInterval / 2, setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
// DposContext: dposContext, }
// statedb: stateDB, }
// } assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
// validators = []common.Address{} assert.Nil(t, dposContext.SetValidators(validators))
// for i := 0; i < maxValidatorSize; i++ { assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) candidateMap = getCandidates(dposContext.CandidateTrie())
// validators = append(validators, validator) assert.Equal(t, maxValidatorSize, len(candidateMap))
// assert.Nil(t, dposContext.BecomeCandidate(validator)) assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(0))])
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2)
// } // epochTime is not complete, all validators mint enough block at least
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ { dposContext, err = types.NewLCPContext(db)
// candidate := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, err)
// assert.Nil(t, dposContext.BecomeCandidate(candidate)) epochContext = &EpochContext{
// } TimeStamp: epochInterval / 2,
// assert.Nil(t, dposContext.SetValidators(validators)) Context: dposContext,
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) statedb: stateDB,
// candidateMap = getCandidates(dposContext.CandidateTrie()) }
// assert.Equal(t, maxValidatorSize *2, len(candidateMap)) validators = []common.Address{}
// for i := 0; i < int(maxValidatorSize); i++ {
// // epochTime is not complete, all validators didn't mint enough block at least validator := common.StringToAddress("addr" + strconv.Itoa(i))
// dposContext, err = types.NewDposContext(db) validators = append(validators, validator)
// assert.Nil(t, err) assert.Nil(t, dposContext.BecomeCandidate(validator))
// epochContext = &EpochContext{ setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2)
// TimeStamp: epochInterval / 2, }
// DposContext: dposContext, for i := int(maxValidatorSize); i < int(maxValidatorSize)*2; i++ {
// statedb: stateDB, candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// } assert.Nil(t, dposContext.BecomeCandidate(candidate))
// validators = []common.Address{} }
// for i := 0; i < maxValidatorSize; i++ { assert.Nil(t, dposContext.SetValidators(validators))
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// validators = append(validators, validator) candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Nil(t, dposContext.BecomeCandidate(validator)) assert.Equal(t, maxValidatorSize*2, len(candidateMap))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2-1)
// } // epochTime is not complete, all validators didn't mint enough block at least
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ { dposContext, err = types.NewLCPContext(db)
// candidate := common.StringToAddress("addr" + strconv.Itoa(i)) assert.Nil(t, err)
// assert.Nil(t, dposContext.BecomeCandidate(candidate)) epochContext = &EpochContext{
// } TimeStamp: epochInterval / 2,
// assert.Nil(t, dposContext.SetValidators(validators)) Context: dposContext,
// assert.Nil(t, epochContext.kickoutValidator(testEpoch)) statedb: stateDB,
// candidateMap = getCandidates(dposContext.CandidateTrie()) }
// assert.Equal(t, maxValidatorSize, len(candidateMap)) validators = []common.Address{}
// for i := 0; i < int(maxValidatorSize); i++ {
// dposContext, err = types.NewDposContext(db) validator := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.Nil(t, err) validators = append(validators, validator)
// epochContext = &EpochContext{ assert.Nil(t, dposContext.BecomeCandidate(validator))
// TimeStamp: epochInterval / 2, setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2-1)
// DposContext: dposContext, }
// statedb: stateDB, for i := int(maxValidatorSize); i < int(maxValidatorSize)*2; i++ {
// } candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.NotNil(t, epochContext.kickoutValidator(testEpoch)) assert.Nil(t, dposContext.BecomeCandidate(candidate))
// dposContext.SetValidators([]common.Address{}) }
// assert.NotNil(t, epochContext.kickoutValidator(testEpoch)) assert.Nil(t, dposContext.SetValidators(validators))
//} assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
//func setTestMintCnt(dposContext *types.DposContext, epoch int64, validator common.Address, count int64) { assert.Equal(t, maxValidatorSize, len(candidateMap))
// for i := int64(0); i < count; i++ {
// updateMintCnt(epoch*epochInterval, epoch*epochInterval+blockInterval, validator, dposContext) dposContext, err = types.NewLCPContext(db)
// } assert.Nil(t, err)
//} epochContext = &EpochContext{
// TimeStamp: epochInterval / 2,
//func getCandidates(candidateTrie *trie.Trie) map[common.Address]bool { Context: dposContext,
// candidateMap := map[common.Address]bool{} statedb: stateDB,
// iter := trie.NewIterator(candidateTrie.NodeIterator(nil)) }
// for iter.Next() { assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap[common.BytesToAddress(iter.Value)] = true dposContext.SetValidators([]common.Address{})
// } assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
// return candidateMap }
//}
// func setTestMintCnt(dposContext *types.LCPContext, epoch int64, validator common.Address, count int64) {
//func TestEpochContextTryElect(t *testing.T) { for i := int64(0); i < count; i++ {
// db, _ := ethdb.NewMemDatabase() updateMintCnt(epoch*epochInterval, epoch*epochInterval+blockInterval, validator, dposContext)
// stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) }
// dposContext, err := types.NewDposContext(db) }
// assert.Nil(t, err)
// epochContext := &EpochContext{ func getCandidates(candidateTrie *trie.Trie) map[common.Address]bool {
// TimeStamp: epochInterval, candidateMap := map[common.Address]bool{}
// DposContext: dposContext, iter := trie.NewIterator(candidateTrie.NodeIterator(nil))
// statedb: stateDB, for iter.Next() {
// } candidateMap[common.BytesToAddress(iter.Value)] = true
// atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2 }
// testEpoch := int64(1) return candidateMap
// validators := []common.Address{} }
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i)) func TestEpochContextTryElect(t *testing.T) {
// validators = append(validators, validator) db := ethdb.NewMemDatabase()
// assert.Nil(t, dposContext.BecomeCandidate(validator)) stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
// assert.Nil(t, dposContext.Delegate(validator, validator)) dposContext, err := types.NewLCPContext(db)
// stateDB.SetBalance(validator, big.NewInt(1)) assert.Nil(t, err)
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1) epochContext := &EpochContext{
// } TimeStamp: epochInterval,
// dposContext.BecomeCandidate(common.StringToAddress("more")) Context: dposContext,
// assert.Nil(t, dposContext.SetValidators(validators)) statedb: stateDB,
// }
// // genesisEpoch == parentEpoch do not kickout maxValidatorSize := int(epochContext.Context.GetMaxValidators())
// genesis := &types.Header{ atLeastMintCnt := epochInterval / blockInterval / int64(maxValidatorSize) / 2
// Time: big.NewInt(0), testEpoch := int64(1)
// } validators := []common.Address{}
// parent := &types.Header{ for i := 0; i < maxValidatorSize; i++ {
// Time: big.NewInt(epochInterval - blockInterval), validator := common.StringToAddress("addr" + strconv.Itoa(i))
// } validators = append(validators, validator)
// oldHash := dposContext.EpochTrie().Hash() assert.Nil(t, dposContext.BecomeCandidate(validator))
// assert.Nil(t, epochContext.tryElect(genesis, parent)) assert.Nil(t, dposContext.Delegate(validator, validator))
// result, err := dposContext.GetValidators() stateDB.SetBalance(validator, big.NewInt(1))
// assert.Nil(t, err) setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// assert.Equal(t, maxValidatorSize, len(result)) }
// for _, validator := range result { dposContext.BecomeCandidate(common.StringToAddress("more"))
// assert.True(t, strings.Contains(validator.Str(), "addr")) assert.Nil(t, dposContext.SetValidators(validators))
// }
// assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) // genesisEpoch == parentEpoch do not kickout
// genesis := &types.Header{
// // genesisEpoch != parentEpoch and have none mintCnt do not kickout Time: big.NewInt(0),
// genesis = &types.Header{ }
// Time: big.NewInt(-epochInterval), parent := &types.Header{
// } Time: big.NewInt(epochInterval - blockInterval),
// parent = &types.Header{ }
// Difficulty: big.NewInt(1), oldHash := dposContext.EpochTrie().Hash()
// Time: big.NewInt(epochInterval - blockInterval), assert.Nil(t, epochContext.tryElect(genesis, parent))
// } result, err := dposContext.GetValidators()
// epochContext.TimeStamp = epochInterval assert.Nil(t, err)
// oldHash = dposContext.EpochTrie().Hash() assert.Equal(t, maxValidatorSize, len(result))
// assert.Nil(t, epochContext.tryElect(genesis, parent)) for _, validator := range result {
// result, err = dposContext.GetValidators() assert.True(t, strings.Contains(validator.Str(), "addr"))
// assert.Nil(t, err) }
// assert.Equal(t, maxValidatorSize, len(result)) assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
// for _, validator := range result {
// assert.True(t, strings.Contains(validator.Str(), "addr")) // genesisEpoch != parentEpoch and have none mintCnt do not kickout
// } genesis = &types.Header{
// assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) Time: big.NewInt(-epochInterval),
// }
// // genesisEpoch != parentEpoch kickout parent = &types.Header{
// genesis = &types.Header{ Difficulty: big.NewInt(1),
// Time: big.NewInt(0), Time: big.NewInt(epochInterval - blockInterval),
// } }
// parent = &types.Header{ epochContext.TimeStamp = epochInterval
// Time: big.NewInt(epochInterval*2 - blockInterval), oldHash = dposContext.EpochTrie().Hash()
// } assert.Nil(t, epochContext.tryElect(genesis, parent))
// epochContext.TimeStamp = epochInterval * 2 result, err = dposContext.GetValidators()
// oldHash = dposContext.EpochTrie().Hash() assert.Nil(t, err)
// assert.Nil(t, epochContext.tryElect(genesis, parent)) assert.Equal(t, maxValidatorSize, len(result))
// result, err = dposContext.GetValidators() for _, validator := range result {
// assert.Nil(t, err) assert.True(t, strings.Contains(validator.Str(), "addr"))
// assert.Equal(t, safeSize, len(result)) }
// moreCnt := 0 assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
// for _, validator := range result {
// if strings.Contains(validator.Str(), "more") { // genesisEpoch != parentEpoch kickout
// moreCnt++ genesis = &types.Header{
// } Time: big.NewInt(0),
// } }
// assert.Equal(t, 1, moreCnt) parent = &types.Header{
// assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) Time: big.NewInt(epochInterval*2 - blockInterval),
// }
// // parentEpoch == currentEpoch do not elect epochContext.TimeStamp = epochInterval * 2
// genesis = &types.Header{ oldHash = dposContext.EpochTrie().Hash()
// Time: big.NewInt(0), assert.Nil(t, epochContext.tryElect(genesis, parent))
// } result, err = dposContext.GetValidators()
// parent = &types.Header{ assert.Nil(t, err)
// Time: big.NewInt(epochInterval), assert.Equal(t, safeSize, len(result))
// } moreCnt := 0
// epochContext.TimeStamp = epochInterval + blockInterval for _, validator := range result {
// oldHash = dposContext.EpochTrie().Hash() if strings.Contains(validator.Str(), "more") {
// assert.Nil(t, epochContext.tryElect(genesis, parent)) moreCnt++
// result, err = dposContext.GetValidators() }
// assert.Nil(t, err) }
// assert.Equal(t, safeSize, len(result)) assert.Equal(t, 1, moreCnt)
// assert.Equal(t, oldHash, dposContext.EpochTrie().Hash()) assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
//}
// parentEpoch == currentEpoch do not elect
genesis = &types.Header{
Time: big.NewInt(0),
}
parent = &types.Header{
Time: big.NewInt(epochInterval),
}
epochContext.TimeStamp = epochInterval + blockInterval
oldHash = dposContext.EpochTrie().Hash()
assert.Nil(t, epochContext.tryElect(genesis, parent))
result, err = dposContext.GetValidators()
assert.Nil(t, err)
assert.Equal(t, safeSize, len(result))
assert.Equal(t, oldHash, dposContext.EpochTrie().Hash())
}

View file

@ -52,6 +52,7 @@ func (ec *EpochContext) countVotes() (votes map[common.Address]*big.Int, err err
} }
delegatorAddr := common.BytesToAddress(delegator) delegatorAddr := common.BytesToAddress(delegator)
weight := statedb.GetBalance(delegatorAddr) weight := statedb.GetBalance(delegatorAddr)
//fmt.Println(weight)
score.Add(score, weight) score.Add(score, weight)
votes[candidateAddr] = score votes[candidateAddr] = score
existDelegator = delegateIterator.Next() existDelegator = delegateIterator.Next()
@ -132,11 +133,13 @@ func (ec *EpochContext) kickoutValidator(epoch int64) error {
func (ec *EpochContext) lookupValidator(now int64) (validator common.Address, err error) { func (ec *EpochContext) lookupValidator(now int64) (validator common.Address, err error) {
validator = common.Address{} validator = common.Address{}
offset := now % ec.Context.GetEpochInterval() epoch_interval:=ec.Context.GetEpochInterval()
offset := now % epoch_interval
block_period:=ec.Context.GetPeriodBlock()
if offset%ec.Context.GetPeriodBlock() != 0 { if offset%ec.Context.GetPeriodBlock() != 0 {
return common.Address{}, ErrInvalidMintBlockTime return common.Address{}, ErrInvalidMintBlockTime
} }
offset /= ec.Context.GetPeriodBlock() offset /= block_period
validators, err := ec.Context.GetValidators() validators, err := ec.Context.GetValidators()
if err != nil { if err != nil {

View file

@ -235,7 +235,7 @@ func (d *LCP) verifySeal(chain consensus.ChainReader, header *types.Header, pare
} else { } else {
parent = chain.GetHeader(header.ParentHash, number-1) parent = chain.GetHeader(header.ParentHash, number-1)
} }
dposContext, err := types.NewLCPContextFromProto(trie.NewDatabase(d.db), parent.LCPContext) dposContext, err := types.NewLCPContextFromProto(d.db, parent.LCPContext)
if err != nil { if err != nil {
return err return err
} }
@ -401,7 +401,7 @@ func (d *LCP) CheckValidator(lastBlock *types.Block, now int64) error {
if err := d.checkDeadline(lastBlock, now); err != nil { if err := d.checkDeadline(lastBlock, now); err != nil {
return err return err
} }
dposContext, err := types.NewLCPContextFromProto(trie.NewDatabase(d.db), lastBlock.Header().LCPContext) dposContext, err := types.NewLCPContextFromProto(d.db, lastBlock.Header().LCPContext)
if err != nil { if err != nil {
return err return err
} }

View file

@ -86,7 +86,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, false, false) gas, _ := IntrinsicGas(data, false, false)
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey) tx, _ := types.SignTx(types.NewTransaction(0, gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
gen.AddTx(tx) gen.AddTx(tx)
} }
} }
@ -119,6 +119,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
} }
to := (from + 1) % naccounts to := (from + 1) % naccounts
tx := types.NewTransaction( tx := types.NewTransaction(
0,
gen.TxNonce(ringAddrs[from]), gen.TxNonce(ringAddrs[from]),
ringAddrs[to], ringAddrs[to],
benchRootFunds, benchRootFunds,

View file

@ -620,7 +620,7 @@ func TestFastVsFullChains(t *testing.T) {
// If the block number is multiple of 3, send a few bonus transactions to the miner // If the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 { if i%3 == 2 {
for j := 0; j < i%4+1; j++ { for j := 0; j < i%4+1; j++ {
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key) tx, err := types.SignTx(types.NewTransaction(0, block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -793,8 +793,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains: // Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain // - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain // - swapped: transaction included at the same block number in the forked chain
postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) postponed, _ := types.SignTx(types.NewTransaction(types.Binary,0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) swapped, _ := types.SignTx(types.NewTransaction(types.Binary, 1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
// Create two transactions that will be dropped by the forked chain: // Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block // - pastDrop: transaction dropped retroactively from a past block
@ -810,13 +810,13 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) pastDrop, _ = types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
case 2: case 2:
freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) freshDrop, _ = types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
gen.AddTx(swapped) // This transaction will be swapped out at the exact height gen.AddTx(swapped) // This transaction will be swapped out at the exact height
@ -835,18 +835,18 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) pastAdd, _ = types.SignTx(types.NewTransaction(types.Binary,gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
case 2: case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) freshAdd, _ = types.SignTx(types.NewTransaction(types.Binary,gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
case 3: case 3:
futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) futureAdd, _ = types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(futureAdd) // This transaction will be added after a full reorg gen.AddTx(futureAdd) // This transaction will be added after a full reorg
} }
}) })
@ -903,7 +903,7 @@ func TestLogReorgs(t *testing.T) {
blockchain.SubscribeRemovedLogsEvent(rmLogsCh) blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
if i == 1 { if i == 1 {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1) tx, err := types.SignTx(types.NewContractCreation(types.Binary, gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
if err != nil { if err != nil {
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
} }
@ -952,7 +952,7 @@ func TestReorgSideEvent(t *testing.T) {
} }
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) { replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil), signer, key1) tx, err := types.SignTx(types.NewContractCreation(types.Binary, gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil), signer, key1)
if i == 2 { if i == 2 {
gen.OffsetTime(-9) gen.OffsetTime(-9)
} }
@ -1080,7 +1080,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction tx *types.Transaction
err error err error
basicTx = func(signer types.Signer) (*types.Transaction, error) { basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) return types.SignTx(types.NewTransaction(types.Binary, block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key)
} }
) )
switch i { switch i {
@ -1143,7 +1143,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction tx *types.Transaction
err error err error
basicTx = func(signer types.Signer) (*types.Transaction, error) { basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) return types.SignTx(types.NewTransaction(types.Binary, block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key)
} }
) )
if i == 0 { if i == 0 {
@ -1190,11 +1190,11 @@ func TestEIP161AccountRemoval(t *testing.T) {
) )
switch i { switch i {
case 0: case 0:
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) tx, err = types.SignTx(types.NewTransaction(types.Binary, block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key)
case 1: case 1:
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) tx, err = types.SignTx(types.NewTransaction(types.Binary, block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key)
case 2: case 2:
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) tx, err = types.SignTx(types.NewTransaction(types.Binary, block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key)
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -1403,7 +1403,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
uniq := uint64(i*numTxs + txi) uniq := uint64(i*numTxs + txi)
recipient := recipientFn(uniq) recipient := recipientFn(uniq)
//recipient := common.BigToAddress(big.NewInt(0).SetUint64(1337 + uniq)) //recipient := common.BigToAddress(big.NewInt(0).SetUint64(1337 + uniq))
tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey) tx, err := types.SignTx(types.NewTransaction(types.Binary,uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
} }

View file

@ -92,7 +92,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
b.SetCoinbase(common.Address{}) b.SetCoinbase(common.Address{})
} }
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) receipt, _, err := ApplyTransaction(b.config,nil, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -54,13 +54,13 @@ func ExampleGenerateChain() {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // In block 1, addr1 sends addr2 some ether.
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) tx, _ := types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
gen.AddTx(tx) gen.AddTx(tx)
case 1: case 1:
// In block 2, addr1 sends some more ether to addr2. // In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3. // addr2 passes it on to addr3.
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) tx1, _ := types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) tx2, _ := types.SignTx(types.NewTransaction(types.Binary, gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(tx1) gen.AddTx(tx1)
gen.AddTx(tx2) gen.AddTx(tx2)
case 2: case 2:

View file

@ -24,26 +24,51 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/pavelkrolevets/go-ethereum/common" "github.com/pavelkrolevets/go-ethereum/common"
"github.com/pavelkrolevets/go-ethereum/consensus/ethash" "github.com/pavelkrolevets/go-ethereum/consensus/ethash"
"github.com/pavelkrolevets/go-ethereum/core/rawdb"
"github.com/pavelkrolevets/go-ethereum/core/vm" "github.com/pavelkrolevets/go-ethereum/core/vm"
"github.com/pavelkrolevets/go-ethereum/ethdb" "github.com/pavelkrolevets/go-ethereum/ethdb"
"github.com/pavelkrolevets/go-ethereum/params" "github.com/pavelkrolevets/go-ethereum/params"
"github.com/pavelkrolevets/go-ethereum/core/types"
"github.com/pavelkrolevets/go-ethereum/core/state"
) )
//func TestDefaultGenesisBlock(t *testing.T) { type bproc struct{}
// block := DefaultGenesisBlock().ToBlock(nil)
// if block.Hash() != params.MainnetGenesisHash { func (bproc) ValidateBody(*types.Block) error { return nil }
// t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainnetGenesisHash) func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
// } return nil
// block = DefaultTestnetGenesisBlock().ToBlock(nil) }
// if block.Hash() != params.TestnetGenesisHash { func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
// t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestnetGenesisHash) return nil, nil, new(big.Int), nil
// } }
//}
func (bproc) ValidateDposState(block *types.Block) error { return nil }
func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {
var chain []*types.Block
for i, difficulty := range d {
header := &types.Header{
Coinbase: common.Address{seed},
Number: big.NewInt(int64(i + 1)),
Difficulty: big.NewInt(int64(difficulty)),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash,
Time: big.NewInt(int64(i) + 1),
}
if i == 0 {
header.ParentHash = genesis.Hash()
} else {
header.ParentHash = chain[i-1].Hash()
}
block := types.NewBlockWithHeader(header)
chain = append(chain, block)
}
return chain
}
func TestSetupGenesis(t *testing.T) { func TestSetupGenesis(t *testing.T) {
var ( var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") customghash = common.HexToHash("0xa4813c30e66d854572733941743e6736f20c0487d32c6b2fe1233946b036f6f5")
customg = Genesis{ customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)}, Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{ Alloc: GenesisAlloc{
@ -60,31 +85,6 @@ func TestSetupGenesis(t *testing.T) {
wantHash common.Hash wantHash common.Hash
wantErr error wantErr error
}{ }{
{
name: "genesis without ChainConfig",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, new(Genesis))
},
wantErr: errGenesisNoConfig,
wantConfig: params.LcpChainConfig,
},
{
name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainnetGenesisHash,
wantConfig: params.LcpChainConfig,
},
{
name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainnetGenesisHash,
wantConfig: params.LcpChainConfig,
},
{ {
name: "custom block in DB, genesis == nil", name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -94,16 +94,6 @@ func TestSetupGenesis(t *testing.T) {
wantHash: customghash, wantHash: customghash,
wantConfig: customg.Config, wantConfig: customg.Config,
}, },
{
name: "custom block in DB, genesis == testnet",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestnetGenesisHash},
wantHash: params.TestnetGenesisHash,
wantConfig: params.TestnetChainConfig,
},
{ {
name: "compatible config in DB", name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -119,12 +109,10 @@ func TestSetupGenesis(t *testing.T) {
// Commit the 'old' genesis block with Homestead transition at #2. // Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg. // Advance to block #4, past the homestead transition block of customg.
genesis := oldcustomg.MustCommit(db) genesis := oldcustomg.MustCommit(db)
bc, _ := NewBlockChain(db,nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}) bc, _ := NewBlockChain(db,nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()
bc.SetValidator(bproc{})
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
bc.InsertChain(blocks)
bc.CurrentBlock() bc.CurrentBlock()
// This should return a compatibility error. // This should return a compatibility error.
return SetupGenesisBlock(db, &customg) return SetupGenesisBlock(db, &customg)
@ -155,7 +143,7 @@ func TestSetupGenesis(t *testing.T) {
t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
} else if err == nil { } else if err == nil {
// Check database content. // Check database content.
stored := rawdb.ReadBlock(db, test.wantHash, 0) stored := GetBlock(db, test.wantHash, 0)
if stored.Hash() != test.wantHash { if stored.Hash() != test.wantHash {
t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash) t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
} }

View file

@ -338,7 +338,7 @@ func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} }
func (b *Block) HashNoNonce() common.Hash { func (b *Block) HashNoNonce() common.Hash {
return b.header.HashNoNonce() return b.header.HashNoNonce()
} }
func (b *Block) LcpCtx() *LCPContext { return b.LCPContext }
// Size returns the true RLP encoded storage size of the block, either by encoding // Size returns the true RLP encoded storage size of the block, either by encoding
// and returning it, or returning a previsouly cached value. // and returning it, or returning a previsouly cached value.
func (b *Block) Size() common.StorageSize { func (b *Block) Size() common.StorageSize {

View file

@ -333,7 +333,10 @@ func (d *LCPContext) BecomeCandidate(candidateAddr common.Address) error {
candidate := candidateAddr.Bytes() candidate := candidateAddr.Bytes()
return d.candidateTrie.TryUpdate(candidate, candidate) return d.candidateTrie.TryUpdate(candidate, candidate)
} }
func (d *LCPContext) BecomeDelegate(delegateAdr common.Address) error {
delegate := delegateAdr.Bytes()
return d.delegateTrie.TryUpdate(delegate, delegate)
}
func (d *LCPContext) Delegate(delegatorAddr, candidateAddr common.Address) error { func (d *LCPContext) Delegate(delegatorAddr, candidateAddr common.Address) error {
delegator, candidate := delegatorAddr.Bytes(), candidateAddr.Bytes() delegator, candidate := delegatorAddr.Bytes(), candidateAddr.Bytes()

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"sync/atomic" "sync/atomic"
"fmt"
"github.com/pavelkrolevets/go-ethereum/common" "github.com/pavelkrolevets/go-ethereum/common"
"github.com/pavelkrolevets/go-ethereum/common/hexutil" "github.com/pavelkrolevets/go-ethereum/common/hexutil"
"github.com/pavelkrolevets/go-ethereum/crypto" "github.com/pavelkrolevets/go-ethereum/crypto"
@ -34,10 +35,31 @@ import (
// transaction type // transaction type
type TxType uint8 type TxType uint8
const (
Binary TxType = iota
LoginCandidate
LogoutCandidate
Delegate
UnDelegate
)
var ( var (
ErrInvalidSig = errors.New("invalid transaction v, r, s values") ErrInvalidSig = errors.New("invalid transaction v, r, s values")
errNoSigner = errors.New("missing signing methods")
ErrInvalidType = errors.New("invalid transaction type")
ErrInvalidAddress = errors.New("invalid transaction payload address")
ErrInvalidAction = errors.New("invalid transaction payload action")
) )
// deriveSigner makes a *best* guess about which signer to use.
func deriveSigner(V *big.Int) Signer {
if V.Sign() != 0 && isProtectedV(V) {
return NewEIP155Signer(deriveChainId(V))
} else {
return HomesteadSigner{}
}
}
type Transaction struct { type Transaction struct {
data txdata data txdata
// caches // caches
@ -47,6 +69,7 @@ type Transaction struct {
} }
type txdata struct { type txdata struct {
Type TxType `json:"type" gencodec:"required"`
AccountNonce uint64 `json:"nonce" gencodec:"required"` AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"` Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"` GasLimit uint64 `json:"gas" gencodec:"required"`
@ -69,20 +92,25 @@ type txdataMarshaling struct {
GasLimit hexutil.Uint64 GasLimit hexutil.Uint64
Amount *hexutil.Big Amount *hexutil.Big
Payload hexutil.Bytes Payload hexutil.Bytes
Type TxType
V *hexutil.Big V *hexutil.Big
R *hexutil.Big R *hexutil.Big
S *hexutil.Big S *hexutil.Big
} }
func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { func NewTransaction(txType TxType, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data) // compatible with raw transaction with to address is empty
if txType != Binary && (to == common.Address{}) {
return newTransaction(txType, nonce, nil, amount, gasLimit, gasPrice, data)
}
return newTransaction(txType, nonce, &to, amount, gasLimit, gasPrice, data)
} }
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { func NewContractCreation(txType TxType, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data) return newTransaction(txType, nonce, nil, amount, gasLimit, gasPrice, data)
} }
func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { func newTransaction(txType TxType, nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
if len(data) > 0 { if len(data) > 0 {
data = common.CopyBytes(data) data = common.CopyBytes(data)
} }
@ -93,6 +121,7 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit
Amount: new(big.Int), Amount: new(big.Int),
GasLimit: gasLimit, GasLimit: gasLimit,
Price: new(big.Int), Price: new(big.Int),
Type: txType,
V: new(big.Int), V: new(big.Int),
R: new(big.Int), R: new(big.Int),
S: new(big.Int), S: new(big.Int),
@ -112,6 +141,22 @@ func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V) return deriveChainId(tx.data.V)
} }
// Valid the transaction when the type isn't the binary
func (tx *Transaction) Validate() error {
if tx.Type() != Binary {
if tx.Value().Uint64() != 0 {
return errors.New("transaction value should be 0")
}
if tx.To() == nil && tx.Type() != LoginCandidate && tx.Type() != LogoutCandidate {
return errors.New("receipient was required")
}
if tx.Data() != nil {
return errors.New("payload should be empty")
}
}
return nil
}
// Protected returns whether the transaction is protected from replay protection. // Protected returns whether the transaction is protected from replay protection.
func (tx *Transaction) Protected() bool { func (tx *Transaction) Protected() bool {
return isProtectedV(tx.data.V) return isProtectedV(tx.data.V)
@ -176,6 +221,7 @@ func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Pri
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
func (tx *Transaction) CheckNonce() bool { return true } func (tx *Transaction) CheckNonce() bool { return true }
func (tx *Transaction) Type() TxType { return tx.data.Type }
// To returns the recipient address of the transaction. // To returns the recipient address of the transaction.
// It returns nil if the transaction is a contract creation. // It returns nil if the transaction is a contract creation.
@ -223,6 +269,7 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
to: tx.data.Recipient, to: tx.data.Recipient,
amount: tx.data.Amount, amount: tx.data.Amount,
data: tx.data.Payload, data: tx.data.Payload,
txType: tx.data.Type,
checkNonce: true, checkNonce: true,
} }
@ -254,6 +301,60 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
return tx.data.V, tx.data.R, tx.data.S return tx.data.V, tx.data.R, tx.data.S
} }
func (tx *Transaction) String() string {
var from, to string
if tx.data.V != nil {
// make a best guess about the signer and use that to derive
// the sender.
signer := deriveSigner(tx.data.V)
if f, err := Sender(signer, tx); err != nil { // derive but don't cache
from = "[invalid sender: invalid sig]"
} else {
from = fmt.Sprintf("%x", f[:])
}
} else {
from = "[invalid sender: nil V field]"
}
if tx.data.Recipient == nil {
to = "[contract creation]"
} else {
to = fmt.Sprintf("%x", tx.data.Recipient[:])
}
enc, _ := rlp.EncodeToBytes(&tx.data)
return fmt.Sprintf(`
TX(%x)
Type: %d
Contract: %v
From: %s
To: %s
Nonce: %v
GasPrice: %#x
GasLimit %#x
Value: %#x
Data: 0x%x
V: %#x
R: %#x
S: %#x
Hex: %x
`,
tx.Hash(),
tx.Type(),
tx.data.Recipient == nil,
from,
to,
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Amount,
tx.data.Payload,
tx.data.V,
tx.data.R,
tx.data.S,
enc,
)
}
// Transactions is a Transaction slice type for basic sorting. // Transactions is a Transaction slice type for basic sorting.
type Transactions []*Transaction type Transactions []*Transaction

View file

@ -142,6 +142,9 @@ func (t *Trie) PrefixIterator(prefix []byte) NodeIterator {
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
// the key after the given start key. // the key after the given start key.
func (t *Trie) NodeIterator(start []byte) NodeIterator { func (t *Trie) NodeIterator(start []byte) NodeIterator {
if t.prefix != nil {
start = append(t.prefix, start...)
}
return newNodeIterator(t, start) return newNodeIterator(t, start)
} }
@ -159,6 +162,9 @@ func (t *Trie) Get(key []byte) []byte {
// The value bytes must not be modified by the caller. // The value bytes must not be modified by the caller.
// If a node was not found in the database, a MissingNodeError is returned. // If a node was not found in the database, a MissingNodeError is returned.
func (t *Trie) TryGet(key []byte) ([]byte, error) { func (t *Trie) TryGet(key []byte) ([]byte, error) {
if t.prefix != nil {
key = append(t.prefix, key...)
}
key = keybytesToHex(key) key = keybytesToHex(key)
value, newroot, didResolve, err := t.tryGet(t.root, key, 0) value, newroot, didResolve, err := t.tryGet(t.root, key, 0)
if err == nil && didResolve { if err == nil && didResolve {
@ -226,6 +232,9 @@ func (t *Trie) Update(key, value []byte) {
// //
// If a node was not found in the database, a MissingNodeError is returned. // If a node was not found in the database, a MissingNodeError is returned.
func (t *Trie) TryUpdate(key, value []byte) error { func (t *Trie) TryUpdate(key, value []byte) error {
if t.prefix != nil {
key = append(t.prefix, key...)
}
k := keybytesToHex(key) k := keybytesToHex(key)
if len(value) != 0 { if len(value) != 0 {
_, n, err := t.insert(t.root, nil, k, valueNode(value)) _, n, err := t.insert(t.root, nil, k, valueNode(value))
@ -322,6 +331,9 @@ func (t *Trie) Delete(key []byte) {
// TryDelete removes any existing value for key from the trie. // TryDelete removes any existing value for key from the trie.
// If a node was not found in the database, a MissingNodeError is returned. // If a node was not found in the database, a MissingNodeError is returned.
func (t *Trie) TryDelete(key []byte) error { func (t *Trie) TryDelete(key []byte) error {
if t.prefix != nil {
key = append(t.prefix, key...)
}
k := keybytesToHex(key) k := keybytesToHex(key)
_, n, err := t.delete(t.root, nil, k) _, n, err := t.delete(t.root, nil, k)
if err != nil { if err != nil {