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
}
func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) }
// BigToAddress returns Address with byte values of b.
// If b is larger than len(h), b will be cropped from the left.
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
@ -219,7 +221,7 @@ func (a Address) Hex() string {
func (a Address) String() string {
return a.Hex()
}
func (a Address) Str() string { return string(a[:]) }
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
// without going through the stringer interface used for logging.
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/ethdb"
"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) {
@ -30,7 +34,7 @@ func TestEpochContextCountVotes(t *testing.T) {
}
balance := int64(5)
db := ethdb.NewMemDatabase()
//bdb := trie.NewDatabase(db)
//dbd := trie.NewDatabase(db)
stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
LCPContext, err := types.NewLCPContext(db)
assert.Nil(t, err)
@ -44,12 +48,31 @@ func TestEpochContextCountVotes(t *testing.T) {
for candidate, electors := range voteMap {
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 {
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))
//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()
//fmt.Println(result)
assert.Nil(t, err)
assert.Equal(t, len(voteMap), len(result))
for candidate, electors := range voteMap {
@ -58,300 +81,316 @@ func TestEpochContextCountVotes(t *testing.T) {
assert.Equal(t, balance*int64(len(electors)), voteCount.Int64())
}
}
//
//func TestLookupValidator(t *testing.T) {
// db, _ := ethdb.NewMemDatabase()
// dposCtx, _ := types.NewDposContext(db)
// mockEpochContext := &EpochContext{
// DposContext: dposCtx,
// }
// validators := []common.Address{
// common.StringToAddress("addr1"),
// common.StringToAddress("addr2"),
// common.StringToAddress("addr3"),
// }
// mockEpochContext.DposContext.SetValidators(validators)
// for i, expected := range validators {
// 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())
// }
// }
// _, err := mockEpochContext.lookupValidator(blockInterval - 1)
// if err != ErrInvalidMintBlockTime {
// t.Errorf("Failed to test lookup validator. err '%v' was expected but got '%v'", ErrInvalidMintBlockTime, err)
// }
//}
//
//func TestEpochContextKickoutValidator(t *testing.T) {
// db, _ := ethdb.NewMemDatabase()
// stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
// dposContext, err := types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext := &EpochContext{
// TimeStamp: epochInterval,
// DposContext: dposContext,
// statedb: stateDB,
// }
// atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2
// testEpoch := int64(1)
//
// // no validator can be kickout, because all validators mint enough block at least
// validators := []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
// }
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap := getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, maxValidatorSize +1, len(candidateMap))
//
// // atLeast a safeSize count candidate will reserve
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval,
// DposContext: dposContext,
// statedb: stateDB,
// }
// validators = []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-int64(i)-1)
// }
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, safeSize, len(candidateMap))
// for i := maxValidatorSize - 1; i >= safeSize; i-- {
// assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(i))])
// }
//
// // all validator will be kickout, because all validators didn't mint enough block at least
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval,
// DposContext: dposContext,
// statedb: stateDB,
// }
// validators = []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// }
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ {
// candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.Nil(t, dposContext.BecomeCandidate(candidate))
// }
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, maxValidatorSize, len(candidateMap))
//
// // only one validator mint count is not enough
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval,
// DposContext: dposContext,
// statedb: stateDB,
// }
// validators = []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// if i == 0 {
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// } else {
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
// }
// }
// assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, maxValidatorSize, len(candidateMap))
// assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(0))])
//
// // epochTime is not complete, all validators mint enough block at least
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval / 2,
// DposContext: dposContext,
// statedb: stateDB,
// }
// validators = []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2)
// }
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ {
// candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.Nil(t, dposContext.BecomeCandidate(candidate))
// }
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, maxValidatorSize *2, len(candidateMap))
//
// // epochTime is not complete, all validators didn't mint enough block at least
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval / 2,
// DposContext: dposContext,
// statedb: stateDB,
// }
// validators = []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2-1)
// }
// for i := maxValidatorSize; i < maxValidatorSize *2; i++ {
// candidate := common.StringToAddress("addr" + strconv.Itoa(i))
// assert.Nil(t, dposContext.BecomeCandidate(candidate))
// }
// assert.Nil(t, dposContext.SetValidators(validators))
// assert.Nil(t, epochContext.kickoutValidator(testEpoch))
// candidateMap = getCandidates(dposContext.CandidateTrie())
// assert.Equal(t, maxValidatorSize, len(candidateMap))
//
// dposContext, err = types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext = &EpochContext{
// TimeStamp: epochInterval / 2,
// DposContext: dposContext,
// statedb: stateDB,
// }
// assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
// dposContext.SetValidators([]common.Address{})
// assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
//}
//
//func setTestMintCnt(dposContext *types.DposContext, epoch int64, validator common.Address, count int64) {
// for i := int64(0); i < count; i++ {
// updateMintCnt(epoch*epochInterval, epoch*epochInterval+blockInterval, validator, dposContext)
// }
//}
//
//func getCandidates(candidateTrie *trie.Trie) map[common.Address]bool {
// candidateMap := map[common.Address]bool{}
// iter := trie.NewIterator(candidateTrie.NodeIterator(nil))
// for iter.Next() {
// candidateMap[common.BytesToAddress(iter.Value)] = true
// }
// return candidateMap
//}
//
//func TestEpochContextTryElect(t *testing.T) {
// db, _ := ethdb.NewMemDatabase()
// stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
// dposContext, err := types.NewDposContext(db)
// assert.Nil(t, err)
// epochContext := &EpochContext{
// TimeStamp: epochInterval,
// DposContext: dposContext,
// statedb: stateDB,
// }
// atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2
// testEpoch := int64(1)
// validators := []common.Address{}
// for i := 0; i < maxValidatorSize; i++ {
// validator := common.StringToAddress("addr" + strconv.Itoa(i))
// validators = append(validators, validator)
// assert.Nil(t, dposContext.BecomeCandidate(validator))
// assert.Nil(t, dposContext.Delegate(validator, validator))
// stateDB.SetBalance(validator, big.NewInt(1))
// setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
// }
// dposContext.BecomeCandidate(common.StringToAddress("more"))
// assert.Nil(t, dposContext.SetValidators(validators))
//
// // genesisEpoch == parentEpoch do not kickout
// genesis := &types.Header{
// Time: big.NewInt(0),
// }
// parent := &types.Header{
// Time: big.NewInt(epochInterval - blockInterval),
// }
// oldHash := dposContext.EpochTrie().Hash()
// assert.Nil(t, epochContext.tryElect(genesis, parent))
// result, err := dposContext.GetValidators()
// assert.Nil(t, err)
// assert.Equal(t, maxValidatorSize, len(result))
// for _, validator := range result {
// assert.True(t, strings.Contains(validator.Str(), "addr"))
// }
// assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
//
// // genesisEpoch != parentEpoch and have none mintCnt do not kickout
// genesis = &types.Header{
// Time: big.NewInt(-epochInterval),
// }
// parent = &types.Header{
// Difficulty: big.NewInt(1),
// Time: big.NewInt(epochInterval - blockInterval),
// }
// epochContext.TimeStamp = epochInterval
// oldHash = dposContext.EpochTrie().Hash()
// assert.Nil(t, epochContext.tryElect(genesis, parent))
// result, err = dposContext.GetValidators()
// assert.Nil(t, err)
// assert.Equal(t, maxValidatorSize, len(result))
// for _, validator := range result {
// assert.True(t, strings.Contains(validator.Str(), "addr"))
// }
// assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
//
// // genesisEpoch != parentEpoch kickout
// genesis = &types.Header{
// Time: big.NewInt(0),
// }
// parent = &types.Header{
// Time: big.NewInt(epochInterval*2 - blockInterval),
// }
// epochContext.TimeStamp = epochInterval * 2
// 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))
// moreCnt := 0
// for _, validator := range result {
// if strings.Contains(validator.Str(), "more") {
// moreCnt++
// }
// }
// 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())
//}
func TestLookupValidator(t *testing.T) {
db:= ethdb.NewMemDatabase()
dposCtx, _ := types.NewLCPContext(db)
mockEpochContext := &EpochContext{
Context: dposCtx,
}
validators := []common.Address{
common.StringToAddress("addr1"),
common.StringToAddress("addr2"),
common.StringToAddress("addr3"),
}
mockEpochContext.Context.SetPeriodBlock(1)
mockEpochContext.Context.SetEpochInterval(86400)
mockEpochContext.Context.SetMaxValidators(3)
blockInterval:=mockEpochContext.Context.GetPeriodBlock()
maxval:=mockEpochContext.Context.GetMaxValidators()
epoch_int:= mockEpochContext.Context.GetEpochInterval()
fmt.Println(blockInterval, maxval,epoch_int)
mockEpochContext.Context.SetValidators(validators)
for i, expected := range validators {
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())
}
}
_, err := mockEpochContext.lookupValidator(blockInterval - 1)
if err != ErrInvalidMintBlockTime {
t.Errorf("Failed to test lookup validator. err '%v' was expected but got '%v'", ErrInvalidMintBlockTime, err)
}
}
func TestEpochContextKickoutValidator(t *testing.T) {
db:= ethdb.NewMemDatabase()
stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
dposContext, err := types.NewLCPContext(db)
assert.Nil(t, err)
epochContext := &EpochContext{
TimeStamp: epochInterval,
Context: dposContext,
statedb: stateDB,
}
epochContext.Context.SetPeriodBlock(1)
epochContext.Context.SetEpochInterval(86400)
epochContext.Context.SetMaxValidators(3)
maxValidatorSize := int(epochContext.Context.GetMaxValidators())
atLeastMintCnt := epochInterval / blockInterval / int64(maxValidatorSize) / 2
testEpoch := int64(1)
// no validator can be kickout, because all validators mint enough block at least
validators := []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
}
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap := getCandidates(dposContext.CandidateTrie())
assert.Equal(t, maxValidatorSize +1, len(candidateMap))
// atLeast a safeSize count candidate will reserve
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval,
Context: dposContext,
statedb: stateDB,
}
validators = []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-int64(i)-1)
}
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap = getCandidates(dposContext.CandidateTrie())
assert.Equal(t, safeSize, len(candidateMap))
for i := int(maxValidatorSize) - 1; i >= safeSize; i-- {
assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(i))])
}
// all validator will be kickout, because all validators didn't mint enough block at least
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval,
Context: dposContext,
statedb: stateDB,
}
validators = []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
}
for i := int(maxValidatorSize); i < int(maxValidatorSize) *2; i++ {
candidate := common.StringToAddress("addr" + strconv.Itoa(i))
assert.Nil(t, dposContext.BecomeCandidate(candidate))
}
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap = getCandidates(dposContext.CandidateTrie())
assert.Equal(t, maxValidatorSize, len(candidateMap))
// only one validator mint count is not enough
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval,
Context: dposContext,
statedb: stateDB,
}
validators = []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
if i == 0 {
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
} else {
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt)
}
}
assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr")))
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap = getCandidates(dposContext.CandidateTrie())
assert.Equal(t, maxValidatorSize, len(candidateMap))
assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(0))])
// epochTime is not complete, all validators mint enough block at least
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval / 2,
Context: dposContext,
statedb: stateDB,
}
validators = []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2)
}
for i := int(maxValidatorSize); i < int(maxValidatorSize) *2; i++ {
candidate := common.StringToAddress("addr" + strconv.Itoa(i))
assert.Nil(t, dposContext.BecomeCandidate(candidate))
}
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap = getCandidates(dposContext.CandidateTrie())
assert.Equal(t, maxValidatorSize *2, len(candidateMap))
// epochTime is not complete, all validators didn't mint enough block at least
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval / 2,
Context: dposContext,
statedb: stateDB,
}
validators = []common.Address{}
for i := 0; i < int(maxValidatorSize); i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2-1)
}
for i := int(maxValidatorSize); i < int(maxValidatorSize) *2; i++ {
candidate := common.StringToAddress("addr" + strconv.Itoa(i))
assert.Nil(t, dposContext.BecomeCandidate(candidate))
}
assert.Nil(t, dposContext.SetValidators(validators))
assert.Nil(t, epochContext.kickoutValidator(testEpoch))
candidateMap = getCandidates(dposContext.CandidateTrie())
assert.Equal(t, maxValidatorSize, len(candidateMap))
dposContext, err = types.NewLCPContext(db)
assert.Nil(t, err)
epochContext = &EpochContext{
TimeStamp: epochInterval / 2,
Context: dposContext,
statedb: stateDB,
}
assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
dposContext.SetValidators([]common.Address{})
assert.NotNil(t, epochContext.kickoutValidator(testEpoch))
}
func setTestMintCnt(dposContext *types.LCPContext, epoch int64, validator common.Address, count int64) {
for i := int64(0); i < count; i++ {
updateMintCnt(epoch*epochInterval, epoch*epochInterval+blockInterval, validator, dposContext)
}
}
func getCandidates(candidateTrie *trie.Trie) map[common.Address]bool {
candidateMap := map[common.Address]bool{}
iter := trie.NewIterator(candidateTrie.NodeIterator(nil))
for iter.Next() {
candidateMap[common.BytesToAddress(iter.Value)] = true
}
return candidateMap
}
func TestEpochContextTryElect(t *testing.T) {
db := ethdb.NewMemDatabase()
stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db))
dposContext, err := types.NewLCPContext(db)
assert.Nil(t, err)
epochContext := &EpochContext{
TimeStamp: epochInterval,
Context: dposContext,
statedb: stateDB,
}
maxValidatorSize:= int(epochContext.Context.GetMaxValidators())
atLeastMintCnt := epochInterval / blockInterval / int64(maxValidatorSize) / 2
testEpoch := int64(1)
validators := []common.Address{}
for i := 0; i < maxValidatorSize; i++ {
validator := common.StringToAddress("addr" + strconv.Itoa(i))
validators = append(validators, validator)
assert.Nil(t, dposContext.BecomeCandidate(validator))
assert.Nil(t, dposContext.Delegate(validator, validator))
stateDB.SetBalance(validator, big.NewInt(1))
setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1)
}
dposContext.BecomeCandidate(common.StringToAddress("more"))
assert.Nil(t, dposContext.SetValidators(validators))
// genesisEpoch == parentEpoch do not kickout
genesis := &types.Header{
Time: big.NewInt(0),
}
parent := &types.Header{
Time: big.NewInt(epochInterval - blockInterval),
}
oldHash := dposContext.EpochTrie().Hash()
assert.Nil(t, epochContext.tryElect(genesis, parent))
result, err := dposContext.GetValidators()
assert.Nil(t, err)
assert.Equal(t, maxValidatorSize, len(result))
for _, validator := range result {
assert.True(t, strings.Contains(validator.Str(), "addr"))
}
assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
// genesisEpoch != parentEpoch and have none mintCnt do not kickout
genesis = &types.Header{
Time: big.NewInt(-epochInterval),
}
parent = &types.Header{
Difficulty: big.NewInt(1),
Time: big.NewInt(epochInterval - blockInterval),
}
epochContext.TimeStamp = epochInterval
oldHash = dposContext.EpochTrie().Hash()
assert.Nil(t, epochContext.tryElect(genesis, parent))
result, err = dposContext.GetValidators()
assert.Nil(t, err)
assert.Equal(t, maxValidatorSize, len(result))
for _, validator := range result {
assert.True(t, strings.Contains(validator.Str(), "addr"))
}
assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash())
// genesisEpoch != parentEpoch kickout
genesis = &types.Header{
Time: big.NewInt(0),
}
parent = &types.Header{
Time: big.NewInt(epochInterval*2 - blockInterval),
}
epochContext.TimeStamp = epochInterval * 2
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))
moreCnt := 0
for _, validator := range result {
if strings.Contains(validator.Str(), "more") {
moreCnt++
}
}
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)
weight := statedb.GetBalance(delegatorAddr)
//fmt.Println(weight)
score.Add(score, weight)
votes[candidateAddr] = score
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) {
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 {
return common.Address{}, ErrInvalidMintBlockTime
}
offset /= ec.Context.GetPeriodBlock()
offset /= block_period
validators, err := ec.Context.GetValidators()
if err != nil {

View file

@ -86,7 +86,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
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)
}
}
@ -119,6 +119,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
}
to := (from + 1) % naccounts
tx := types.NewTransaction(
0,
gen.TxNonce(ringAddrs[from]),
ringAddrs[to],
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 i%3 == 2 {
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 {
panic(err)
}
@ -793,8 +793,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains:
// - postponed: transaction included at a later block 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)
swapped, _ := types.SignTx(types.NewTransaction(1, 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(types.Binary, 1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
// Create two transactions that will be dropped by the forked chain:
// - 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) {
switch i {
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(postponed) // This transaction will be postponed till block #3 in the fork
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(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) {
switch i {
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
case 2:
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
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
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
}
})
@ -903,7 +903,7 @@ func TestLogReorgs(t *testing.T) {
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
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 {
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) {
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 {
gen.OffsetTime(-9)
}
@ -1080,7 +1080,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction
err 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 {
@ -1143,7 +1143,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction
err 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 {
@ -1190,11 +1190,11 @@ func TestEIP161AccountRemoval(t *testing.T) {
)
switch i {
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:
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:
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 {
t.Fatal(err)
@ -1403,7 +1403,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
uniq := uint64(i*numTxs + txi)
recipient := recipientFn(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 {
b.Error(err)
}

View file

@ -92,7 +92,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
b.SetCoinbase(common.Address{})
}
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 {
panic(err)
}

View file

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

View file

@ -24,26 +24,51 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/pavelkrolevets/go-ethereum/common"
"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/ethdb"
"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) {
// block := DefaultGenesisBlock().ToBlock(nil)
// if block.Hash() != params.MainnetGenesisHash {
// t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainnetGenesisHash)
// }
// block = DefaultTestnetGenesisBlock().ToBlock(nil)
// if block.Hash() != params.TestnetGenesisHash {
// t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestnetGenesisHash)
// }
//}
type bproc struct{}
func (bproc) ValidateBody(*types.Block) error { return nil }
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
return nil
}
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
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) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
customghash = common.HexToHash("0xa4813c30e66d854572733941743e6736f20c0487d32c6b2fe1233946b036f6f5")
customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{
@ -60,31 +85,6 @@ func TestSetupGenesis(t *testing.T) {
wantHash common.Hash
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",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
@ -94,16 +94,6 @@ func TestSetupGenesis(t *testing.T) {
wantHash: customghash,
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",
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.
// Advance to block #4, past the homestead transition block of customg.
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()
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
bc.InsertChain(blocks)
bc.SetValidator(bproc{})
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
bc.CurrentBlock()
// This should return a compatibility error.
return SetupGenesisBlock(db, &customg)
@ -141,7 +129,7 @@ func TestSetupGenesis(t *testing.T) {
}
for _, test := range tests {
db := ethdb.NewMemDatabase()
db:= ethdb.NewMemDatabase()
config, hash, err := test.fn(db)
// Check the return values.
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())
} else if err == nil {
// Check database content.
stored := rawdb.ReadBlock(db, test.wantHash, 0)
stored := GetBlock(db, test.wantHash, 0)
if 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
for i, tx := range block.Transactions() {
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 {
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
// for the transaction, gas used and an error if the transaction failed,
// 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))
if err != nil {
return nil, 0, err
@ -100,6 +100,11 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
if err != nil {
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
var root []byte
if config.IsByzantium(header.Number) {
@ -124,3 +129,19 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
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 {
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
// and returning it, or returning a previsouly cached value.
func (b *Block) Size() common.StorageSize {

View file

@ -333,7 +333,10 @@ func (d *LCPContext) BecomeCandidate(candidateAddr common.Address) error {
candidate := candidateAddr.Bytes()
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 {
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/crypto"
"github.com/pavelkrolevets/go-ethereum/rlp"
"fmt"
)
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
var (
ErrInvalidSig = errors.New("invalid transaction v, r, s values")
// transaction type
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 {
data txdata
// caches
@ -44,6 +70,7 @@ type Transaction struct {
}
type txdata struct {
Type TxType `json:"type" gencodec:"required"`
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"`
@ -66,20 +93,25 @@ type txdataMarshaling struct {
GasLimit hexutil.Uint64
Amount *hexutil.Big
Payload hexutil.Bytes
Type TxType
V *hexutil.Big
R *hexutil.Big
S *hexutil.Big
}
func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
func NewTransaction(txType TxType, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
// 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 {
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
func NewContractCreation(txType TxType, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
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 {
data = common.CopyBytes(data)
}
@ -90,6 +122,7 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit
Amount: new(big.Int),
GasLimit: gasLimit,
Price: new(big.Int),
Type: txType,
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
@ -109,6 +142,22 @@ func (tx *Transaction) ChainId() *big.Int {
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.
func (tx *Transaction) Protected() bool {
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) Nonce() uint64 { return tx.data.AccountNonce }
func (tx *Transaction) CheckNonce() bool { return true }
func (tx *Transaction) Type() TxType { return tx.data.Type }
// To returns the recipient address of the transaction.
// 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,
amount: tx.data.Amount,
data: tx.data.Payload,
txType: tx.data.Type,
checkNonce: true,
}
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
}
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.
type Transactions []*Transaction
@ -387,6 +493,7 @@ type Message struct {
gasPrice *big.Int
data []byte
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 {
@ -399,6 +506,7 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
gasPrice: gasPrice,
data: data,
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) Data() []byte { return m.data }
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
// the key after the given start key.
func (t *Trie) NodeIterator(start []byte) NodeIterator {
if t.prefix != nil {
start = append(t.prefix, 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.
// If a node was not found in the database, a MissingNodeError is returned.
func (t *Trie) TryGet(key []byte) ([]byte, error) {
if t.prefix != nil {
key = append(t.prefix, key...)
}
key = keybytesToHex(key)
value, newroot, didResolve, err := t.tryGet(t.root, key, 0)
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.
func (t *Trie) TryUpdate(key, value []byte) error {
if t.prefix != nil {
key = append(t.prefix, key...)
}
k := keybytesToHex(key)
if len(value) != 0 {
_, 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.
// If a node was not found in the database, a MissingNodeError is returned.
func (t *Trie) TryDelete(key []byte) error {
if t.prefix != nil {
key = append(t.prefix, key...)
}
k := keybytesToHex(key)
_, n, err := t.delete(t.root, nil, k)
if err != nil {