From fb640ddeac3abab0baba352085a26d50af0bb22b Mon Sep 17 00:00:00 2001
From: pavelkrolevets
You can download the Ethereum Wallet from https://github.com/ethereum/mist/releases. You can download the Ethereum Wallet from https://github.com/pavelkrolevets/mist/releases.
You can download the Mist browser from https://github.com/ethereum/mist/releases. You can download the Mist browser from https://github.com/pavelkrolevets/mist/releases.ethereumwallet --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}
- mist --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}
- eth --config {{.CppGenesis}} --datadir $HOME/.{{.Network}} --peerset "{{.CppBootnodes}}"
You can find cpp-ethereum at https://github.com/ethereum/cpp-ethereum/.
+You can find cpp-ethereum at https://github.com/pavelkrolevets/cpp-ethereum/.
@@ -401,7 +401,7 @@ try! node?.start();pyethapp -c eth.genesis="$(cat {{.PythonGenesis}})" -c eth.network_id={{.NetworkID}} -c data_dir=$HOME/.config/pyethapp/{{.Network}} -c discovery.bootstrap_nodes="[{{.PythonBootnodes}}]" -c eth.block.HOMESTEAD_FORK_BLKNUM={{.Homestead}} -c eth.block.ANTI_DOS_FORK_BLKNUM={{.Tangerine}} -c eth.block.SPURIOUS_DRAGON_FORK_BLKNUM={{.Spurious}} -c eth.block.METROPOLIS_FORK_BLKNUM={{.Byzantium}} -c eth.block.DAO_FORK_BLKNUM=18446744073709551615 run --console
You can find pyethapp at https://github.com/ethereum/pyethapp/.
+You can find pyethapp at https://github.com/pavelkrolevets/pyethapp/.
diff --git a/common/types_test.go b/common/types_test.go index 7095ccd019..1bfa7eb4ed 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -126,7 +126,7 @@ func TestAddressHexChecksum(t *testing.T) { Input string Output string }{ - // Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#specification + // Test cases from https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-55.md#specification {"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"}, {"0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"}, {"0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"}, @@ -154,7 +154,7 @@ func BenchmarkAddressHex(b *testing.B) { func TestMixedcaseAccount_Address(t *testing.T) { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md + // https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-55.md // Note: 0X{checksum_addr} is not valid according to spec above var res []struct { diff --git a/consensus/dpos/api.go b/consensus/dpos/api.go index cc7b8a93db..2748b0efd1 100644 --- a/consensus/dpos/api.go +++ b/consensus/dpos/api.go @@ -17,10 +17,10 @@ package dpos import ( - "github.com/pavelkrolevets/go-ethereum/common" - "github.com/pavelkrolevets/go-ethereum/consensus" - "github.com/pavelkrolevets/go-ethereum/core/types" - "github.com/pavelkrolevets/go-ethereum/rpc" + "github.com/meitu/go-ethereum/common" + "github.com/meitu/go-ethereum/consensus" + "github.com/meitu/go-ethereum/core/types" + "github.com/meitu/go-ethereum/rpc" "math/big" ) diff --git a/consensus/dpos/dpos.go b/consensus/dpos/dpos.go index d8e9f78277..d53d0f8cba 100644 --- a/consensus/dpos/dpos.go +++ b/consensus/dpos/dpos.go @@ -33,9 +33,9 @@ const ( blockInterval = int64(1) epochInterval = int64(86400) - maxValidatorSize = 3 - safeSize = maxValidatorSize*2/3 + 1 - consensusSize = maxValidatorSize*2/3 + 1 + maxValidatorSize = 1 + safeSize = 1 //maxValidatorSize*2/3 + 1 + consensusSize = 1 //maxValidatorSize*2/3 + 1 ) var ( diff --git a/consensus/dpos/dpos_test.go b/consensus/dpos/dpos_test.go index 7f79ace3aa..784fbbce9a 100644 --- a/consensus/dpos/dpos_test.go +++ b/consensus/dpos/dpos_test.go @@ -5,10 +5,10 @@ import ( "encoding/binary" - "github.com/pavelkrolevets/go-ethereum/common" - "github.com/pavelkrolevets/go-ethereum/core/types" - "github.com/pavelkrolevets/go-ethereum/ethdb" - "github.com/pavelkrolevets/go-ethereum/trie" + "github.com/meitu/go-ethereum/common" + "github.com/meitu/go-ethereum/core/types" + "github.com/meitu/go-ethereum/ethdb" + "github.com/meitu/go-ethereum/trie" "github.com/stretchr/testify/assert" ) diff --git a/consensus/dpos/epoch_context.go b/consensus/dpos/epoch_context.go index cbda686c1e..03cf821604 100644 --- a/consensus/dpos/epoch_context.go +++ b/consensus/dpos/epoch_context.go @@ -8,12 +8,12 @@ import ( "math/rand" "sort" - "github.com/pavelkrolevets/go-ethereum/common" - "github.com/pavelkrolevets/go-ethereum/core/state" - "github.com/pavelkrolevets/go-ethereum/core/types" - "github.com/pavelkrolevets/go-ethereum/crypto" - "github.com/pavelkrolevets/go-ethereum/log" - "github.com/pavelkrolevets/go-ethereum/trie" + "github.com/meitu/go-ethereum/common" + "github.com/meitu/go-ethereum/core/state" + "github.com/meitu/go-ethereum/core/types" + "github.com/meitu/go-ethereum/crypto" + "github.com/meitu/go-ethereum/log" + "github.com/meitu/go-ethereum/trie" ) type EpochContext struct { diff --git a/consensus/dpos/epoch_context_test.go b/consensus/dpos/epoch_context_test.go index e8a2d2fde7..8a2fab6589 100644 --- a/consensus/dpos/epoch_context_test.go +++ b/consensus/dpos/epoch_context_test.go @@ -6,11 +6,11 @@ import ( "strings" "testing" - "github.com/pavelkrolevets/go-ethereum/common" - "github.com/pavelkrolevets/go-ethereum/core/state" - "github.com/pavelkrolevets/go-ethereum/core/types" - "github.com/pavelkrolevets/go-ethereum/ethdb" - "github.com/pavelkrolevets/go-ethereum/trie" + "github.com/meitu/go-ethereum/common" + "github.com/meitu/go-ethereum/core/state" + "github.com/meitu/go-ethereum/core/types" + "github.com/meitu/go-ethereum/ethdb" + "github.com/meitu/go-ethereum/trie" "github.com/stretchr/testify/assert" ) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 63220bb748..fd8095da03 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -321,7 +321,7 @@ var ( // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Byzantium rules. func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { - // https://github.com/ethereum/EIPs/issues/100. + // https://github.com/pavelkrolevets/EIPs/issues/100. // algorithm: // diff = (parent_diff + // (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) @@ -356,7 +356,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { x.Set(params.MinimumDifficulty) } // calculate a fake block number for the ice-age delay: - // https://github.com/ethereum/EIPs/pull/669 + // https://github.com/pavelkrolevets/EIPs/pull/669 // fake_block_number = max(0, block.number - 3_000_000) fakeBlockNumber := new(big.Int) if parent.Number.Cmp(big2999999) >= 0 { @@ -380,7 +380,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Homestead rules. func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md + // https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-2.md // algorithm: // diff = (parent_diff + // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) diff --git a/contracts/ens/README.md b/contracts/ens/README.md index c09b47e39d..92d1930fc2 100644 --- a/contracts/ens/README.md +++ b/contracts/ens/README.md @@ -2,7 +2,7 @@ ## Usage -Full documentation for the Ethereum Name Service [can be found as EIP 137](https://github.com/ethereum/EIPs/issues/137). +Full documentation for the Ethereum Name Service [can be found as EIP 137](https://github.com/pavelkrolevets/EIPs/issues/137). This package offers a simple binding that streamlines the registration of arbitrary UTF8 domain names to swarm content hashes. ## Development diff --git a/core/types/block.go b/core/types/block.go index a02c049ecf..606f73ff59 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -25,6 +25,7 @@ import ( "sync/atomic" "time" "unsafe" + "fmt" "github.com/pavelkrolevets/go-ethereum/common" "github.com/pavelkrolevets/go-ethereum/common/hexutil" @@ -70,6 +71,8 @@ func (n *BlockNonce) UnmarshalText(input []byte) error { type Header struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Validator common.Address `json:"validator" gencodec:"required"` + DposContext *DposContextProto `json:"dposContext" gencodec:"required"` Coinbase common.Address `json:"miner" gencodec:"required"` Root common.Hash `json:"stateRoot" gencodec:"required"` TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` @@ -107,6 +110,7 @@ func (h *Header) HashNoNonce() common.Hash { return rlpHash([]interface{}{ h.ParentHash, h.UncleHash, + h.Validator, h.Coinbase, h.Root, h.TxHash, @@ -159,6 +163,7 @@ type Block struct { // inter-peer block relay. ReceivedAt time.Time ReceivedFrom interface{} + DposContext *DposContext } // DeprecatedTd is an old relic for extracting the TD of a block. It is in the @@ -253,6 +258,11 @@ func CopyHeader(h *Header) *Header { cpy.Extra = make([]byte, len(h.Extra)) copy(cpy.Extra, h.Extra) } + // add dposContextProto to header + cpy.DposContext = &DposContextProto{} + if h.DposContext != nil { + cpy.DposContext = h.DposContext + } return &cpy } @@ -311,6 +321,7 @@ func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) } func (b *Block) Bloom() Bloom { return b.header.Bloom } +func (b *Block) Validator() common.Address { return b.header.Validator } func (b *Block) Coinbase() common.Address { return b.header.Coinbase } func (b *Block) Root() common.Hash { return b.header.Root } func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } @@ -360,7 +371,10 @@ func (b *Block) WithSeal(header *Header) *Block { header: &cpy, transactions: b.transactions, uncles: b.uncles, + // add dposcontext + DposContext: b.DposContext, } + } // WithBody returns a new block with the given transaction and uncle contents. @@ -388,6 +402,42 @@ func (b *Block) Hash() common.Hash { return v } +func (b *Block) String() string { + str := fmt.Sprintf(`Block(#%v): Size: %v { +MinerHash: %x +%v +Transactions: +%v +Uncles: +%v +} +`, b.Number(), b.Size(), b.header.HashNoNonce(), b.header, b.transactions, b.uncles) + return str +} + +func (h *Header) String() string { + return fmt.Sprintf(`Header(%x): +[ + ParentHash: %x + UncleHash: %x + Validator: %x + Coinbase: %x + Root: %x + TxSha %x + ReceiptSha: %x + DposContext: %x + Bloom: %x + Difficulty: %v + Number: %v + GasLimit: %v + GasUsed: %v + Time: %v + Extra: %s + MixDigest: %x + Nonce: %x +]`, h.Hash(), h.ParentHash, h.UncleHash, h.Validator, h.Coinbase, h.Root, h.TxHash, h.ReceiptHash, h.DposContext, h.Bloom, h.Difficulty, h.Number, h.GasLimit, h.GasUsed, h.Time, h.Extra, h.MixDigest, h.Nonce) +} + type Blocks []*Block type BlockBy func(b1, b2 *Block) bool diff --git a/core/types/dpos_context.go b/core/types/dpos_context.go new file mode 100644 index 0000000000..bd6d1ef3cd --- /dev/null +++ b/core/types/dpos_context.go @@ -0,0 +1,359 @@ +package types + +import ( + "bytes" + "errors" + "fmt" + + "github.com/pavelkrolevets/go-ethereum/common" + "github.com/pavelkrolevets/go-ethereum/crypto/sha3" + "github.com/pavelkrolevets/go-ethereum/ethdb" + "github.com/pavelkrolevets/go-ethereum/rlp" + "github.com/pavelkrolevets/go-ethereum/trie" +) + +type DposContext struct { + epochTrie *trie.Trie + delegateTrie *trie.Trie + voteTrie *trie.Trie + candidateTrie *trie.Trie + mintCntTrie *trie.Trie + + db trie.Database +} + +var ( + epochPrefix = []byte("epoch-") + delegatePrefix = []byte("delegate-") + votePrefix = []byte("vote-") + candidatePrefix = []byte("candidate-") + mintCntPrefix = []byte("mintCnt-") +) + +func NewEpochTrie(root common.Hash, db trie.Database) (*trie.Trie, error) { + return trie.NewTrieWithPrefix(root, epochPrefix, db) +} + +func NewDelegateTrie(root common.Hash, db trie.Database) (*trie.Trie, error) { + return trie.NewTrieWithPrefix(root, delegatePrefix, db) +} + +func NewVoteTrie(root common.Hash, db trie.Database) (*trie.Trie, error) { + return trie.NewTrieWithPrefix(root, votePrefix, db) +} + +func NewCandidateTrie(root common.Hash, db trie.Database) (*trie.Trie, error) { + return trie.NewTrieWithPrefix(root, candidatePrefix, db) +} + +func NewMintCntTrie(root common.Hash, db trie.Database) (*trie.Trie, error) { + return trie.NewTrieWithPrefix(root, mintCntPrefix, db) +} + +func NewDposContext(db trie.Database) (*DposContext, error) { + epochTrie, err := NewEpochTrie(common.Hash{}, db) + if err != nil { + return nil, err + } + delegateTrie, err := NewDelegateTrie(common.Hash{}, db) + if err != nil { + return nil, err + } + voteTrie, err := NewVoteTrie(common.Hash{}, db) + if err != nil { + return nil, err + } + candidateTrie, err := NewCandidateTrie(common.Hash{}, db) + if err != nil { + return nil, err + } + mintCntTrie, err := NewMintCntTrie(common.Hash{}, db) + if err != nil { + return nil, err + } + return &DposContext{ + epochTrie: epochTrie, + delegateTrie: delegateTrie, + voteTrie: voteTrie, + candidateTrie: candidateTrie, + mintCntTrie: mintCntTrie, + db: db, + }, nil +} + +func NewDposContextFromProto(db trie.Database, ctxProto *DposContextProto) (*DposContext, error) { + epochTrie, err := NewEpochTrie(ctxProto.EpochHash, db) + if err != nil { + return nil, err + } + delegateTrie, err := NewDelegateTrie(ctxProto.DelegateHash, db) + if err != nil { + return nil, err + } + voteTrie, err := NewVoteTrie(ctxProto.VoteHash, db) + if err != nil { + return nil, err + } + candidateTrie, err := NewCandidateTrie(ctxProto.CandidateHash, db) + if err != nil { + return nil, err + } + mintCntTrie, err := NewMintCntTrie(ctxProto.MintCntHash, db) + if err != nil { + return nil, err + } + return &DposContext{ + epochTrie: epochTrie, + delegateTrie: delegateTrie, + voteTrie: voteTrie, + candidateTrie: candidateTrie, + mintCntTrie: mintCntTrie, + db: db, + }, nil +} + +func (d *DposContext) Copy() *DposContext { + epochTrie := *d.epochTrie + delegateTrie := *d.delegateTrie + voteTrie := *d.voteTrie + candidateTrie := *d.candidateTrie + mintCntTrie := *d.mintCntTrie + return &DposContext{ + epochTrie: &epochTrie, + delegateTrie: &delegateTrie, + voteTrie: &voteTrie, + candidateTrie: &candidateTrie, + mintCntTrie: &mintCntTrie, + } +} + +func (d *DposContext) Root() (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, d.epochTrie.Hash()) + rlp.Encode(hw, d.delegateTrie.Hash()) + rlp.Encode(hw, d.candidateTrie.Hash()) + rlp.Encode(hw, d.voteTrie.Hash()) + rlp.Encode(hw, d.mintCntTrie.Hash()) + hw.Sum(h[:0]) + return h +} + +func (d *DposContext) Snapshot() *DposContext { + return d.Copy() +} + +func (d *DposContext) RevertToSnapShot(snapshot *DposContext) { + d.epochTrie = snapshot.epochTrie + d.delegateTrie = snapshot.delegateTrie + d.candidateTrie = snapshot.candidateTrie + d.voteTrie = snapshot.voteTrie + d.mintCntTrie = snapshot.mintCntTrie +} + +func (d *DposContext) FromProto(dcp *DposContextProto) error { + var err error + d.epochTrie, err = NewEpochTrie(dcp.EpochHash, d.db) + if err != nil { + return err + } + d.delegateTrie, err = NewDelegateTrie(dcp.DelegateHash, d.db) + if err != nil { + return err + } + d.candidateTrie, err = NewCandidateTrie(dcp.CandidateHash, d.db) + if err != nil { + return err + } + d.voteTrie, err = NewVoteTrie(dcp.VoteHash, d.db) + if err != nil { + return err + } + d.mintCntTrie, err = NewMintCntTrie(dcp.MintCntHash, d.db) + return err +} + +type DposContextProto struct { + EpochHash common.Hash `json:"epochRoot" gencodec:"required"` + DelegateHash common.Hash `json:"delegateRoot" gencodec:"required"` + CandidateHash common.Hash `json:"candidateRoot" gencodec:"required"` + VoteHash common.Hash `json:"voteRoot" gencodec:"required"` + MintCntHash common.Hash `json:"mintCntRoot" gencodec:"required"` +} + +func (d *DposContext) ToProto() *DposContextProto { + return &DposContextProto{ + EpochHash: d.epochTrie.Hash(), + DelegateHash: d.delegateTrie.Hash(), + CandidateHash: d.candidateTrie.Hash(), + VoteHash: d.voteTrie.Hash(), + MintCntHash: d.mintCntTrie.Hash(), + } +} + +func (p *DposContextProto) Root() (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, p.EpochHash) + rlp.Encode(hw, p.DelegateHash) + rlp.Encode(hw, p.CandidateHash) + rlp.Encode(hw, p.VoteHash) + rlp.Encode(hw, p.MintCntHash) + hw.Sum(h[:0]) + return h +} + +func (d *DposContext) KickoutCandidate(candidateAddr common.Address) error { + candidate := candidateAddr.Bytes() + err := d.candidateTrie.TryDelete(candidate) + if err != nil { + if _, ok := err.(*trie.MissingNodeError); !ok { + return err + } + } + iter := trie.NewIterator(d.delegateTrie.PrefixIterator(candidate)) + for iter.Next() { + delegator := iter.Value + key := append(candidate, delegator...) + err = d.delegateTrie.TryDelete(key) + if err != nil { + if _, ok := err.(*trie.MissingNodeError); !ok { + return err + } + } + v, err := d.voteTrie.TryGet(delegator) + if err != nil { + if _, ok := err.(*trie.MissingNodeError); !ok { + return err + } + } + if err == nil && bytes.Equal(v, candidate) { + err = d.voteTrie.TryDelete(delegator) + if err != nil { + if _, ok := err.(*trie.MissingNodeError); !ok { + return err + } + } + } + } + return nil +} + +func (d *DposContext) BecomeCandidate(candidateAddr common.Address) error { + candidate := candidateAddr.Bytes() + return d.candidateTrie.TryUpdate(candidate, candidate) +} + +func (d *DposContext) Delegate(delegatorAddr, candidateAddr common.Address) error { + delegator, candidate := delegatorAddr.Bytes(), candidateAddr.Bytes() + + // the candidate must be candidate + candidateInTrie, err := d.candidateTrie.TryGet(candidate) + if err != nil { + return err + } + if candidateInTrie == nil { + return errors.New("invalid candidate to delegate") + } + + // delete old candidate if exists + oldCandidate, err := d.voteTrie.TryGet(delegator) + if err != nil { + if _, ok := err.(*trie.MissingNodeError); !ok { + return err + } + } + if oldCandidate != nil { + d.delegateTrie.Delete(append(oldCandidate, delegator...)) + } + if err = d.delegateTrie.TryUpdate(append(candidate, delegator...), delegator); err != nil { + return err + } + return d.voteTrie.TryUpdate(delegator, candidate) +} + +func (d *DposContext) UnDelegate(delegatorAddr, candidateAddr common.Address) error { + delegator, candidate := delegatorAddr.Bytes(), candidateAddr.Bytes() + + // the candidate must be candidate + candidateInTrie, err := d.candidateTrie.TryGet(candidate) + if err != nil { + return err + } + if candidateInTrie == nil { + return errors.New("invalid candidate to undelegate") + } + + oldCandidate, err := d.voteTrie.TryGet(delegator) + if err != nil { + return err + } + if !bytes.Equal(candidate, oldCandidate) { + return errors.New("mismatch candidate to undelegate") + } + + if err = d.delegateTrie.TryDelete(append(candidate, delegator...)); err != nil { + return err + } + return d.voteTrie.TryDelete(delegator) +} + +func (d *DposContext) CommitTo(dbw trie.DatabaseWriter) (*DposContextProto, error) { + epochRoot, err := d.epochTrie.CommitTo(dbw) + if err != nil { + return nil, err + } + delegateRoot, err := d.delegateTrie.CommitTo(dbw) + if err != nil { + return nil, err + } + voteRoot, err := d.voteTrie.CommitTo(dbw) + if err != nil { + return nil, err + } + candidateRoot, err := d.candidateTrie.CommitTo(dbw) + if err != nil { + return nil, err + } + mintCntRoot, err := d.mintCntTrie.CommitTo(dbw) + if err != nil { + return nil, err + } + return &DposContextProto{ + EpochHash: epochRoot, + DelegateHash: delegateRoot, + VoteHash: voteRoot, + CandidateHash: candidateRoot, + MintCntHash: mintCntRoot, + }, nil +} + +func (d *DposContext) CandidateTrie() *trie.Trie { return d.candidateTrie } +func (d *DposContext) DelegateTrie() *trie.Trie { return d.delegateTrie } +func (d *DposContext) VoteTrie() *trie.Trie { return d.voteTrie } +func (d *DposContext) EpochTrie() *trie.Trie { return d.epochTrie } +func (d *DposContext) MintCntTrie() *trie.Trie { return d.mintCntTrie } +func (d *DposContext) DB() ethdb.Database { return d.db } +func (dc *DposContext) SetEpoch(epoch *trie.Trie) { dc.epochTrie = epoch } +func (dc *DposContext) SetDelegate(delegate *trie.Trie) { dc.delegateTrie = delegate } +func (dc *DposContext) SetVote(vote *trie.Trie) { dc.voteTrie = vote } +func (dc *DposContext) SetCandidate(candidate *trie.Trie) { dc.candidateTrie = candidate } +func (dc *DposContext) SetMintCnt(mintCnt *trie.Trie) { dc.mintCntTrie = mintCnt } + +func (dc *DposContext) GetValidators() ([]common.Address, error) { + var validators []common.Address + key := []byte("validator") + validatorsRLP := dc.epochTrie.Get(key) + if err := rlp.DecodeBytes(validatorsRLP, &validators); err != nil { + return nil, fmt.Errorf("failed to decode validators: %s", err) + } + return validators, nil +} + +func (dc *DposContext) SetValidators(validators []common.Address) error { + key := []byte("validator") + validatorsRLP, err := rlp.EncodeToBytes(validators) + if err != nil { + return fmt.Errorf("failed to encode validators to rlp bytes: %s", err) + } + dc.epochTrie.Update(key, validatorsRLP) + return nil +} diff --git a/core/types/dpos_context_test.go b/core/types/dpos_context_test.go new file mode 100644 index 0000000000..7de8fceb62 --- /dev/null +++ b/core/types/dpos_context_test.go @@ -0,0 +1,178 @@ +package types + +import ( + "testing" + + "github.com/pavelkrolevets/go-ethereum/common" + "github.com/pavelkrolevets/go-ethereum/ethdb" + "github.com/pavelkrolevets/go-ethereum/trie" + "github.com/stretchr/testify/assert" +) + +func TestDposContextSnapshot(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + dposContext, err := NewDposContext(db) + assert.Nil(t, err) + + snapshot := dposContext.Snapshot() + assert.Equal(t, dposContext.Root(), snapshot.Root()) + assert.NotEqual(t, dposContext, snapshot) + + // change dposContext + assert.Nil(t, dposContext.BecomeCandidate(common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6c"))) + assert.NotEqual(t, dposContext.Root(), snapshot.Root()) + + // revert snapshot + dposContext.RevertToSnapShot(snapshot) + assert.Equal(t, dposContext.Root(), snapshot.Root()) + assert.NotEqual(t, dposContext, snapshot) +} + +func TestDposContextBecomeCandidate(t *testing.T) { + candidates := []common.Address{ + common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"), + common.HexToAddress("0xa60a3886b552ff9992cfcd208ec1152079e046c2"), + common.HexToAddress("0x4e080e49f62694554871e669aeb4ebe17c4a9670"), + } + db, _ := ethdb.NewMemDatabase() + dposContext, err := NewDposContext(db) + assert.Nil(t, err) + for _, candidate := range candidates { + assert.Nil(t, dposContext.BecomeCandidate(candidate)) + } + + candidateMap := map[common.Address]bool{} + candidateIter := trie.NewIterator(dposContext.candidateTrie.NodeIterator(nil)) + for candidateIter.Next() { + candidateMap[common.BytesToAddress(candidateIter.Value)] = true + } + assert.Equal(t, len(candidates), len(candidateMap)) + for _, candidate := range candidates { + assert.True(t, candidateMap[candidate]) + } +} + +func TestDposContextKickoutCandidate(t *testing.T) { + candidates := []common.Address{ + common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"), + common.HexToAddress("0xa60a3886b552ff9992cfcd208ec1152079e046c2"), + common.HexToAddress("0x4e080e49f62694554871e669aeb4ebe17c4a9670"), + } + db, _ := ethdb.NewMemDatabase() + dposContext, err := NewDposContext(db) + assert.Nil(t, err) + for _, candidate := range candidates { + assert.Nil(t, dposContext.BecomeCandidate(candidate)) + assert.Nil(t, dposContext.Delegate(candidate, candidate)) + } + + kickIdx := 1 + assert.Nil(t, dposContext.KickoutCandidate(candidates[kickIdx])) + candidateMap := map[common.Address]bool{} + candidateIter := trie.NewIterator(dposContext.candidateTrie.NodeIterator(nil)) + for candidateIter.Next() { + candidateMap[common.BytesToAddress(candidateIter.Value)] = true + } + voteIter := trie.NewIterator(dposContext.voteTrie.NodeIterator(nil)) + voteMap := map[common.Address]bool{} + for voteIter.Next() { + voteMap[common.BytesToAddress(voteIter.Value)] = true + } + for i, candidate := range candidates { + delegateIter := trie.NewIterator(dposContext.delegateTrie.PrefixIterator(candidate.Bytes())) + if i == kickIdx { + assert.False(t, delegateIter.Next()) + assert.False(t, candidateMap[candidate]) + assert.False(t, voteMap[candidate]) + continue + } + assert.True(t, delegateIter.Next()) + assert.True(t, candidateMap[candidate]) + assert.True(t, voteMap[candidate]) + } +} + +func TestDposContextDelegateAndUnDelegate(t *testing.T) { + candidate := common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e") + newCandidate := common.HexToAddress("0xa60a3886b552ff9992cfcd208ec1152079e046c2") + delegator := common.HexToAddress("0x4e080e49f62694554871e669aeb4ebe17c4a9670") + db, _ := ethdb.NewMemDatabase() + dposContext, err := NewDposContext(db) + assert.Nil(t, err) + assert.Nil(t, dposContext.BecomeCandidate(candidate)) + assert.Nil(t, dposContext.BecomeCandidate(newCandidate)) + + // delegator delegate to not exist candidate + candidateIter := trie.NewIterator(dposContext.candidateTrie.NodeIterator(nil)) + candidateMap := map[string]bool{} + for candidateIter.Next() { + candidateMap[string(candidateIter.Value)] = true + } + assert.NotNil(t, dposContext.Delegate(delegator, common.HexToAddress("0xab"))) + + // delegator delegate to old candidate + assert.Nil(t, dposContext.Delegate(delegator, candidate)) + delegateIter := trie.NewIterator(dposContext.delegateTrie.PrefixIterator(candidate.Bytes())) + if assert.True(t, delegateIter.Next()) { + assert.Equal(t, append(delegatePrefix, append(candidate.Bytes(), delegator.Bytes()...)...), delegateIter.Key) + assert.Equal(t, delegator, common.BytesToAddress(delegateIter.Value)) + } + voteIter := trie.NewIterator(dposContext.voteTrie.NodeIterator(nil)) + if assert.True(t, voteIter.Next()) { + assert.Equal(t, append(votePrefix, delegator.Bytes()...), voteIter.Key) + assert.Equal(t, candidate, common.BytesToAddress(voteIter.Value)) + } + + // delegator delegate to new candidate + assert.Nil(t, dposContext.Delegate(delegator, newCandidate)) + delegateIter = trie.NewIterator(dposContext.delegateTrie.PrefixIterator(candidate.Bytes())) + assert.False(t, delegateIter.Next()) + delegateIter = trie.NewIterator(dposContext.delegateTrie.PrefixIterator(newCandidate.Bytes())) + if assert.True(t, delegateIter.Next()) { + assert.Equal(t, append(delegatePrefix, append(newCandidate.Bytes(), delegator.Bytes()...)...), delegateIter.Key) + assert.Equal(t, delegator, common.BytesToAddress(delegateIter.Value)) + } + voteIter = trie.NewIterator(dposContext.voteTrie.NodeIterator(nil)) + if assert.True(t, voteIter.Next()) { + assert.Equal(t, append(votePrefix, delegator.Bytes()...), voteIter.Key) + assert.Equal(t, newCandidate, common.BytesToAddress(voteIter.Value)) + } + + // delegator undelegate to not exist candidate + assert.NotNil(t, dposContext.UnDelegate(common.HexToAddress("0x00"), candidate)) + + // delegator undelegate to old candidate + assert.NotNil(t, dposContext.UnDelegate(delegator, candidate)) + + // delegator undelegate to new candidate + assert.Nil(t, dposContext.UnDelegate(delegator, newCandidate)) + delegateIter = trie.NewIterator(dposContext.delegateTrie.PrefixIterator(newCandidate.Bytes())) + assert.False(t, delegateIter.Next()) + voteIter = trie.NewIterator(dposContext.voteTrie.NodeIterator(nil)) + assert.False(t, voteIter.Next()) +} + +func TestDposContextValidators(t *testing.T) { + validators := []common.Address{ + common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"), + common.HexToAddress("0xa60a3886b552ff9992cfcd208ec1152079e046c2"), + common.HexToAddress("0x4e080e49f62694554871e669aeb4ebe17c4a9670"), + } + + db, _ := ethdb.NewMemDatabase() + dposContext, err := NewDposContext(db) + assert.Nil(t, err) + + assert.Nil(t, dposContext.SetValidators(validators)) + + result, err := dposContext.GetValidators() + assert.Nil(t, err) + assert.Equal(t, len(validators), len(result)) + validatorMap := map[common.Address]bool{} + for _, validator := range validators { + validatorMap[validator] = true + } + for _, validator := range result { + assert.True(t, validatorMap[validator]) + } +} diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index fe3c3bec55..4c8d897a5f 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -29,7 +29,7 @@ import ( ) // The values in those tests are from the Transaction Tests -// at github.com/ethereum/tests. +// at github.com/pavelkrolevets/tests. var ( emptyTx = NewTransaction( 0, diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index ae91cca607..3e138c1731 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -110,7 +110,7 @@ func TestByteOp(t *testing.T) { } func TestSHL(t *testing.T) { - // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left + // Testcases from https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left tests := []twoOperandTest{ {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"}, @@ -128,7 +128,7 @@ func TestSHL(t *testing.T) { } func TestSHR(t *testing.T) { - // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right + // Testcases from https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right tests := []twoOperandTest{ {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, @@ -146,7 +146,7 @@ func TestSHR(t *testing.T) { } func TestSAR(t *testing.T) { - // Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right + // Testcases from https://github.com/pavelkrolevets/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right tests := []twoOperandTest{ {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"}, {"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"}, diff --git a/dashboard/assets.go b/dashboard/assets.go index f3e7cf9815..bbc8508a77 100644 --- a/dashboard/assets.go +++ b/dashboard/assets.go @@ -32727,7 +32727,7 @@ var _bundleJs = []byte((((((((((`!function(modules) { }, _react2.default.createElement("span", { style: _common.styles.light }, "Commit "), _react2.default.createElement("a", { - href: "https://github.com/ethereum/go-ethereum/commit/" + general.commit, + href: "https://github.com/pavelkrolevets/go-ethereum/commit/" + general.commit, target: "_blank", style: { color: "inherit", diff --git a/eth/filters/api.go b/eth/filters/api.go index e9afd4172a..3739a28005 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -101,7 +101,7 @@ func (api *PublicFilterAPI) timeoutLoop() { // It is part of the filter package because this filter can be used through the // `eth_getFilterChanges` polling method that is also used for log filters. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { var ( pendingTxs = make(chan []common.Hash) @@ -171,7 +171,7 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su // NewBlockFilter creates a filter that fetches blocks that are imported into the chain. // It is part of the filter package since polling goes with eth_getFilterChanges. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_newblockfilter func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { var ( headers = make(chan *types.Header) @@ -287,7 +287,7 @@ type FilterCriteria ethereum.FilterQuery // // In case "fromBlock" > "toBlock" an error is returned. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_newfilter func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { logs := make(chan []*types.Log) logsSub, err := api.events.SubscribeLogs(ethereum.FilterQuery(crit), logs) @@ -322,7 +322,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { // GetLogs returns logs matching the given argument that are stored within the state. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_getlogs func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { var filter *Filter if crit.BlockHash != nil { @@ -351,7 +351,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ // UninstallFilter removes the filter with the given filter id. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_uninstallfilter func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { api.filtersMu.Lock() f, found := api.filters[id] @@ -369,7 +369,7 @@ func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { // GetFilterLogs returns the logs for the filter with the given id. // If the filter could not be found an empty array of logs is returned. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_getfilterlogs func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) { api.filtersMu.Lock() f, found := api.filters[id] @@ -410,7 +410,7 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty // For pending transaction and block filters the result is []common.Hash. // (pending)Log filters return []Log. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_getfilterchanges func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { api.filtersMu.Lock() defer api.filtersMu.Unlock() diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 80dbcc8617..690a6a2865 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1249,7 +1249,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod // // The account associated with addr must be unlocked. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign +// https://github.com/pavelkrolevets/wiki/wiki/JSON-RPC#eth_sign func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} diff --git a/params/config.go b/params/config.go index 7ba6cc91fd..934a847160 100644 --- a/params/config.go +++ b/params/config.go @@ -78,21 +78,34 @@ var ( }, } + DposChainConfig = &ChainConfig{ + ChainID: big.NewInt(1515), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP150Hash: common.Hash{}, + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + + Dpos: &DposConfig{}, + } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -109,7 +122,7 @@ type ChainConfig struct { DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork - // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) + // EIP150 implements the Gas price changes (https://github.com/pavelkrolevets/EIPs/issues/150) EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) @@ -122,6 +135,7 @@ type ChainConfig struct { // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` + Dpos *DposConfig `json:"dpos,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -143,6 +157,16 @@ func (c *CliqueConfig) String() string { return "clique" } +// DposConfig is the consensus engine configs for delegated proof-of-stake based sealing. +type DposConfig struct { + Validators []common.Address `json:"validators"` // Genesis validator list +} + +// String implements the stringer interface, returning the consensus engine details. +func (d *DposConfig) String() string { + return "dpos" +} + // String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { var engine interface{} @@ -151,6 +175,8 @@ func (c *ChainConfig) String() string { engine = c.Ethash case c.Clique != nil: engine = c.Clique + case c.Dpos !=nil: + engine = c.Dpos default: engine = "unknown" } diff --git a/signer/core/abihelper_test.go b/signer/core/abihelper_test.go index 538ba9bbb7..fd3fa58db6 100644 --- a/signer/core/abihelper_test.go +++ b/signer/core/abihelper_test.go @@ -71,7 +71,7 @@ func TestNewUnpacker(t *testing.T) { [10]byte{49, 50, 51, 52, 53, 54, 55, 56, 57, 48}, common.Hex2Bytes("48656c6c6f2c20776f726c6421"), }, - }, { // https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#examples + }, { // https://github.com/pavelkrolevets/wiki/wiki/Ethereum-Contract-ABI#examples `[{"type":"function","name":"sam","inputs":[{"type":"bytes"},{"type":"bool"},{"type":"uint256[]"}]}]`, // "dave", true and [1,2,3] "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", @@ -139,7 +139,7 @@ func TestCalldataDecoding(t *testing.T) { "42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", // Too short compareAndApprove "a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", - // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI + // From https://github.com/pavelkrolevets/wiki/wiki/Ethereum-Contract-ABI // contains a bool with illegal values "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", } { @@ -151,7 +151,7 @@ func TestCalldataDecoding(t *testing.T) { //Expected success for _, hexdata := range []string{ - // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI + // From https://github.com/pavelkrolevets/wiki/wiki/Ethereum-Contract-ABI "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", "a52c101e0000000000000000000000000000000000000000000000000000000000000012", "a52c101eFFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 2a6527714d..4e49c4c467 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -151,7 +151,7 @@ func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { } } -/* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II +/* See https://github.com/pavelkrolevets/tests/wiki/Blockchain-Tests-II Whether a block is valid or not is a bit subtle, it's defined by presence of blockHeader, transactions and uncleHeaders fields. If they are missing, the block is diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 26b9109936..3dc64769dd 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -38,7 +38,7 @@ import ( ) // StateTest checks transaction processing without block context. -// See https://github.com/ethereum/EIPs/issues/176 for the test format specification. +// See https://github.com/pavelkrolevets/EIPs/issues/176 for the test format specification. type StateTest struct { json stJSON } @@ -218,7 +218,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { dataHex := tx.Data[ps.Indexes.Data] valueHex := tx.Value[ps.Indexes.Value] gasLimit := tx.GasLimit[ps.Indexes.Gas] - // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203 + // Value, Data hex encoding is messy: https://github.com/pavelkrolevets/tests/issues/203 value := new(big.Int) if valueHex != "0x" { v, ok := math.ParseBig256(valueHex) diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 1131d1cf28..27dc3ef9e6 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -34,7 +34,7 @@ import ( ) // VMTest checks EVM execution without block or transaction context. -// See https://github.com/ethereum/tests/wiki/VM-Tests for the test format specification. +// See https://github.com/pavelkrolevets/tests/wiki/VM-Tests for the test format specification. type VMTest struct { json vmJSON } diff --git a/trie/database.go b/trie/database.go index 47282ec87b..0345c2788c 100644 --- a/trie/database.go +++ b/trie/database.go @@ -58,6 +58,14 @@ type DatabaseReader interface { Has(key []byte) (bool, error) } +// DatabaseWriter wraps the Put method of a backing store for the trie. +type DatabaseWriter interface { + // Put stores the mapping key->value in the database. + // Implementations must not hold onto the value bytes, the trie + // will reuse the slice across calls to Put. + Put(key, value []byte) error +} + // Database is an intermediate write layer between the trie data structures and // the disk database. The aim is to accumulate trie writes in-memory and only // periodically flush a couple tries to disk, garbage collecting the remainder. diff --git a/trie/iterator.go b/trie/iterator.go index e4379c1c67..8963d4f311 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -573,3 +573,94 @@ func (it *unionIterator) Error() error { } return nil } + +type prefixIterator struct { + prefix []byte + nodeIterator NodeIterator +} + +// newPrefixIterator constructs a NodeIterator, iterates over elements in trie that +// has common prefix. +func newPrefixIterator(trie *Trie, prefix []byte) NodeIterator { + if trie.Hash() == emptyState { + return new(prefixIterator) + } + // nodeIterator will convert prefix to hex + nodeIt := newNodeIterator(trie, prefix) + prefix = keybytesToHex(prefix) + return &prefixIterator{ + nodeIterator: nodeIt, + prefix: prefix[:len(prefix)-1], // remove the hex terminator + } +} + +// hasPrefix return whether the nodeIterator has common prefix +func (it *prefixIterator) hasPrefix() bool { + return bytes.HasPrefix(it.nodeIterator.Path(), it.prefix) +} + +func (it *prefixIterator) Hash() common.Hash { + if it.hasPrefix() { + return it.nodeIterator.Hash() + } + return common.Hash{} +} + +func (it *prefixIterator) Parent() common.Hash { + if it.hasPrefix() { + it.nodeIterator.Parent() + } + return common.Hash{} +} + +func (it *prefixIterator) Leaf() bool { + if it.hasPrefix() { + return it.nodeIterator.Leaf() + } + return false +} + +func (it *prefixIterator) LeafBlob() []byte { + if it.hasPrefix() { + return it.nodeIterator.LeafBlob() + } + return nil +} + +func (it *prefixIterator) LeafKey() []byte { + if it.hasPrefix() { + return it.nodeIterator.LeafKey() + } + return nil +} + +func (it *prefixIterator) Path() []byte { + if it.hasPrefix() { + return it.nodeIterator.Path() + } + return nil +} + +// Next moves the iterator to the next node, returning whether there are any +// further nodes which has common prefix. In case of an internal error this method +// returns false and sets the Error field to the encountered failure. +// If `descend` is false, skips iterating over any subnodes of the current node. +func (it *prefixIterator) Next(descend bool) bool { + if it.nodeIterator.Next(descend) { + if it.hasPrefix() { + return true + } + } + return false +} + +func (it *prefixIterator) Error() error { + return it.nodeIterator.Error() +} + +func (it *prefixIterator) LeafProof() [][]byte { + if it.hasPrefix() { + return it.nodeIterator.LeafProof() + } + return nil +} diff --git a/trie/trie.go b/trie/trie.go index a59802b241..16854bc7ac 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -25,6 +25,8 @@ import ( "github.com/pavelkrolevets/go-ethereum/crypto" "github.com/pavelkrolevets/go-ethereum/log" "github.com/pavelkrolevets/go-ethereum/metrics" + "github.com/pavelkrolevets/go-ethereum/crypto/sha3" + ) var ( @@ -54,6 +56,10 @@ func CacheUnloads() int64 { return cacheUnloadCounter.Count() } +func init() { + sha3.NewKeccak256().Sum(emptyState[:0]) +} + // LeafCallback is a callback type invoked when a trie operation reaches a leaf // node. It's used by state sync and commit to allow handling external references // between account and storage tries. @@ -65,10 +71,10 @@ type LeafCallback func(leaf []byte, parent common.Hash) error // // Trie is not safe for concurrent use. type Trie struct { - db *Database + db Database root node originalRoot common.Hash - + prefix []byte // Cache generation values. // cachegen increases by one with each commit operation. // new nodes are tagged with the current generation and unloaded @@ -93,14 +99,17 @@ func (t *Trie) newFlag() nodeFlag { // trie is initially empty and does not require a database. Otherwise, // New will panic if db is nil and returns a MissingNodeError if root does // not exist in the database. Accessing the trie loads nodes from db on demand. -func New(root common.Hash, db *Database) (*Trie, error) { - if db == nil { - panic("trie.New called without a database") - } +func New(root common.Hash, db Database) (*Trie, error) { + trie := &Trie{ db: db, originalRoot: root, } + + if db == nil { + panic("trie.New called without a database") + } + if root != (common.Hash{}) && root != emptyRoot { rootnode, err := trie.resolveHash(root[:], nil) if err != nil { @@ -110,6 +119,25 @@ func New(root common.Hash, db *Database) (*Trie, error) { } return trie, nil } +// Creates trie with prefix for dpos content +func NewTrieWithPrefix(root common.Hash, prefix []byte, db Database) (*Trie, error) { + trie, err := New(root, db) + if err != nil { + return nil, err + } + trie.prefix = prefix + return trie, nil +} + + +// PrefixIterator returns an iterator that returns nodes of the trie which has the prefix path specificed +// Iteration starts at the key after the given start key. +func (t *Trie) PrefixIterator(prefix []byte) NodeIterator { + if t.prefix != nil { + prefix = append(t.prefix, prefix...) + } + return newPrefixIterator(t, prefix) +} // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // the key after the given start key. diff --git a/vendor/github.com/ethereum/ethash/src/libethash/io.h b/vendor/github.com/ethereum/ethash/src/libethash/io.h index 7a27089c7d..75cdcef7f9 100644 --- a/vendor/github.com/ethereum/ethash/src/libethash/io.h +++ b/vendor/github.com/ethereum/ethash/src/libethash/io.h @@ -38,7 +38,7 @@ extern "C" { // 10 is for maximum number of digits of a uint32_t (for REVISION) // 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of // the seedhash and last 1 is for the null terminating character -// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG +// Reference: https://github.com/pavelkrolevets/wiki/wiki/Ethash-DAG #define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1) /// Possible return values of @see ethash_io_prepare enum ethash_io_rc { @@ -80,7 +80,7 @@ enum ethash_io_rc { * data directory. If it does not exist it's created. * @param[in] seedhash The seedhash of the current block number, used in the * naming of the file as can be seen from the spec at: - * https://github.com/ethereum/wiki/wiki/Ethash-DAG + * https://github.com/pavelkrolevets/wiki/wiki/Ethash-DAG * @param[out] output_file If there was no failure then this will point to an open * file descriptor. User is responsible for closing it. * In the case of memo match then the file is open on read @@ -175,7 +175,7 @@ char* ethash_io_create_filename( /** * Gets the default directory name for the DAG depending on the system * - * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * The spec defining this directory is here: https://github.com/pavelkrolevets/wiki/wiki/Ethash-DAG * * @param[out] strbuf A string buffer of sufficient size to keep the * null termninated string of the directory name