ADDED LCP engine

This commit is contained in:
pavelkrolevets 2018-08-24 13:39:21 +08:00
parent 197fcd5445
commit 5f8a201d68
13 changed files with 567 additions and 389 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

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

@ -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)
@ -141,7 +129,7 @@ func TestSetupGenesis(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
db := ethdb.NewMemDatabase() db:= ethdb.NewMemDatabase()
config, hash, err := test.fn(db) config, hash, err := test.fn(db)
// Check the return values. // Check the return values.
if !reflect.DeepEqual(err, test.wantErr) { if !reflect.DeepEqual(err, test.wantErr) {
@ -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

@ -68,7 +68,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// 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, nil, 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,7 +85,7 @@ 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
@ -100,6 +100,11 @@ 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) {
@ -124,3 +129,19 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
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

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

@ -27,14 +27,40 @@ import (
"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"
"github.com/pavelkrolevets/go-ethereum/rlp" "github.com/pavelkrolevets/go-ethereum/rlp"
"fmt"
) )
//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
var ( // transaction type
ErrInvalidSig = errors.New("invalid transaction v, r, s values") type TxType uint8
const (
Binary TxType = iota
LoginCandidate
LogoutCandidate
Delegate
UnDelegate
) )
var (
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
@ -44,6 +70,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"`
@ -66,20 +93,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)
} }
@ -90,6 +122,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),
@ -109,6 +142,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)
@ -173,6 +222,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.
@ -220,7 +270,9 @@ 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,
} }
var err error var err error
@ -251,6 +303,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
@ -387,6 +493,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 {
@ -399,6 +506,7 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
gasPrice: gasPrice, gasPrice: gasPrice,
data: data, data: data,
checkNonce: checkNonce, checkNonce: checkNonce,
} }
} }
@ -410,3 +518,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 }

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 {