"github.com/vapor/common"
"github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
+ dpos "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/errors"
config.CommonConfig = config.DefaultConfig()
consensus.SoloNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
dirPath, err := ioutil.TempDir(".", "")
if err != nil {
store := leveldb.NewStore(testDB)
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ var engine engine.Engine
+ switch config.CommonConfig.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
+ chain, err := protocol.NewChain(store, txPool, engine)
if err != nil {
t.Fatal(err)
}
import (
"context"
"encoding/json"
+ "fmt"
"github.com/vapor/config"
"github.com/vapor/blockchain/txbuilder"
"github.com/vapor/common"
"github.com/vapor/consensus"
+ dpos "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/errors"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
+ "github.com/vapor/protocol/vm"
"github.com/vapor/protocol/vm/vmutil"
)
type DopsAction struct {
Accounts *Manager
bc.AssetAmount
- From string `json:"from"`
- To string `json:"to"`
- Fee uint64 `json:"fee"`
- UseUnconfirmed bool `json:"use_unconfirmed"`
- TxType uint32 `json:"tx_type"`
- Height uint64 `json:"height"`
+ DposType uint32 `json:"dpos_type"`
+ Address string `json:"address"`
+ Name string `json:"name"`
+ Forgers []string `json:"forgers"`
+ UseUnconfirmed bool `json:"use_unconfirmed"`
}
func (a *DopsAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) error {
if a.AssetId.IsZero() {
missing = append(missing, "asset_id")
}
- if a.From == "" {
- missing = append(missing, "from")
+ if a.Address == "" {
+ missing = append(missing, "address")
}
- if a.To == "" {
- missing = append(missing, "to")
+ if len(missing) > 0 {
+ return txbuilder.MissingFieldsError(missing...)
}
-
- if types.TxType(a.TxType) < types.Binary || types.TxType(a.TxType) > types.ConfirmTx {
+ if types.TxType(a.DposType) < types.Binary || types.TxType(a.DposType) > types.CancelVote {
return errors.New("tx type of dpos is error")
}
+ var (
+ referenceData []byte
+ data []byte
+ op vm.Op
+ err error
+ )
+
+ switch types.TxType(a.DposType) {
+ case types.Binary:
+ case types.Registe:
+ if a.Name == "" {
+ return errors.New("name is null for dpos Registe")
+ }
+ if a.Amount < consensus.RegisrerForgerFee {
+ return errors.New("The transaction fee is 100000000 for dpos Registe")
+ }
- txType := types.TxType(a.TxType)
+ if dpos.GDpos.HaveDelegate(a.Name, a.Address) {
+ return errors.New("Forger name has registe")
+ }
- if len(missing) > 0 {
- return txbuilder.MissingFieldsError(missing...)
- }
- res, err := a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Amount, a.UseUnconfirmed, false)
- if err != nil {
- return errors.Wrap(err, "reserving utxos")
- }
+ data, err = json.Marshal(&dpos.RegisterForgerData{Name: a.Name})
+ if err != nil {
+ return err
+ }
+ op = vm.OP_REGISTE
+ case types.Vote:
+ if len(a.Forgers) == 0 {
+ return errors.New("Forgers is null for dpos Vote")
+ }
- // Cancel the reservation if the build gets rolled back.
- b.OnRollback(func() { a.Accounts.utxoKeeper.Cancel(res.id) })
- for _, r := range res.utxos {
- txInput, sigInst, err := DposTx(a.From, a.To, a.Amount, r, txType, a.Height)
+ if a.Amount < consensus.VoteForgerFee {
+ return errors.New("The transaction fee is 10000000 for dpos Registe")
+ }
+
+ for _, forger := range a.Forgers {
+ if dpos.GDpos.HaveVote(a.Address, forger) {
+ return fmt.Errorf("delegate name: %s is voted", forger)
+ }
+ }
+
+ data, err = json.Marshal(&dpos.VoteForgerData{Forgers: a.Forgers})
if err != nil {
- return errors.Wrap(err, "creating inputs")
+ return err
}
- if err = b.AddInput(txInput, sigInst); err != nil {
- return errors.Wrap(err, "adding inputs")
+ op = vm.OP_VOTE
+ case types.CancelVote:
+ if len(a.Forgers) == 0 {
+ return errors.New("Forgers is null for dpos CancelVote")
+ }
+ if a.Amount < consensus.CancelVoteForgerFee {
+ return errors.New("The transaction fee is 10000000 for dpos Registe")
+ }
+
+ for _, forger := range a.Forgers {
+ if !dpos.GDpos.HaveVote(a.Address, forger) {
+ return fmt.Errorf("delegate name: %s is not voted", forger)
+ }
}
+
+ data, err = json.Marshal(&dpos.CancelVoteForgerData{Forgers: a.Forgers})
+ if err != nil {
+ return err
+ }
+ op = vm.OP_REVOKE
+ }
+
+ msg := dpos.DposMsg{
+ Type: op,
+ Data: data,
+ }
+
+ referenceData, err = json.Marshal(&msg)
+ if err != nil {
+ return err
}
+ b.SetReferenceData(referenceData)
- res, err = a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Fee, a.UseUnconfirmed, true)
+ res, err := a.Accounts.utxoKeeper.ReserveByAddress(a.Address, a.AssetId, a.Amount, a.UseUnconfirmed, false)
if err != nil {
return errors.Wrap(err, "reserving utxos")
}
}
}
if res.change >= 0 {
- address, err := common.DecodeAddress(a.From, &consensus.ActiveNetParams)
+ address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
if err != nil {
return err
}
sigInst := &txbuilder.SigningInstruction{}
var xpubs []chainkd.XPub
var xprv chainkd.XPrv
- xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
+ xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.XPrv))
xpubs = append(xpubs, xprv.XPub())
quorum := len(xpubs)
if u.Address == "" {
sigInst := &txbuilder.SigningInstruction{}
var xpubs []chainkd.XPub
var xprv chainkd.XPrv
- xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
+ xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.XPrv))
xpubs = append(xpubs, xprv.XPub())
quorum := len(xpubs)
if u.Address == "" {
m.Handle("/get-side-raw-transaction", jsonHandler(a.getSideRawTransaction))
m.Handle("/build-mainchain-tx", jsonHandler(a.buildMainChainTxForContract))
m.Handle("/sign-with-key", jsonHandler(a.signWithKey))
- m.Handle("/dpos", jsonHandler(a.dpos))
- // registe
- // vote
- // cancelvote
+ m.Handle("/sign-with-xprv", jsonHandler(a.signWithPriKey))
// listdelegates
+ m.Handle("/list-delegates", jsonHandler(a.listDelegates))
// getdelegatevotes
- // getdelegatefunds
+ m.Handle("/get-delegate-votes", jsonHandler(a.getDelegateVotes))
// listvoteddelegates
+ m.Handle("/list-voted-delegates", jsonHandler(a.listVotedDelegates))
// listreceivedvotes
- // getirreversibleblock
+ m.Handle("/list-received-votes", jsonHandler(a.listReceivedVotes))
+
+ m.Handle("/get-address-balance", jsonHandler(a.getAddressBalance))
} else {
log.Warn("Please enable wallet")
}
}
func TestEstimateTxGas(t *testing.T) {
- tmplStr := `{"allow_additional_actions":false,"raw_transaction":"0701a8d30201010060015ef39ac9f5a6b0db3eb4b2a54a8d012ef5626c1da5462bc97c7a0a1c11bd8e39bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0d6e0ce120001160014b29b9e1b31018d5161e33d0c465bbb6dd1df1556010002013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacfc9bc512011600142a38b1e022d42414b76a11b7b63075d08fe90b77000139ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14011600145427f2318811979c908eb2f06d439d134aa156fe00","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"6c420aa025610d323a55c29a8692e2f909b176e88c3bfc8b78cb64ead1bd5db2c6d8492346d12acea177ed0fa4a4579c4bdf020c8cf10fa99cad72f3d5b7de04","derivation_path":["010100000000000000","0e00000000000000"]}],"signatures":null},{"type":"data","value":"512d84b99c93d51729215de3d796390f762f74692306863e3f3bcb0090b399f4"}]}]}`
+ tmplStr := `{"raw_transaction":"0701a8d30201010060015e7e8cf2b20c310f7a8197d598f04a04470eda4d59470661d124b688b507525a9dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c8afa0250101160014b6fd589b689b2e7a8772c5c0a855734851c2f72a010001013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086d8f02401160014b6fd589b689b2e7a8772c5c0a855734851c2f72a00667b2254797065223a3231302c2244617461223a2265794a6d62334a6e5a584a7a496a7062496e5a7a625446784d32316d625752324e6a52714d6e70684d4755326548646c64475a77634745304e326833633368325a7a6b7a5a6e5635655730695858303d227d","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"67e1a63e43dbd7148aa3ffe5a8e869ff5d89f687d1d29f6224a95bd0ce3b3eb61e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445","derivation_path":null}],"signatures":null},{"type":"data","value":"67e1a63e43dbd7148aa3ffe5a8e869ff5d89f687d1d29f6224a95bd0ce3b3eb6"}]}],"fee":100000000,"allow_additional_actions":false}`
template := txbuilder.Template{}
err := json.Unmarshal([]byte(tmplStr), &template)
if err != nil {
}{
{
path: "/estimate-transaction-gas",
- tmplStr: `{"allow_additional_actions":false,"raw_transaction":"0701a8d30201010060015ef39ac9f5a6b0db3eb4b2a54a8d012ef5626c1da5462bc97c7a0a1c11bd8e39bdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0d6e0ce120001160014b29b9e1b31018d5161e33d0c465bbb6dd1df1556010002013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacfc9bc512011600142a38b1e022d42414b76a11b7b63075d08fe90b77000139ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14011600145427f2318811979c908eb2f06d439d134aa156fe00","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"6c420aa025610d323a55c29a8692e2f909b176e88c3bfc8b78cb64ead1bd5db2c6d8492346d12acea177ed0fa4a4579c4bdf020c8cf10fa99cad72f3d5b7de04","derivation_path":["010100000000000000","0e00000000000000"]}],"signatures":null},{"type":"data","value":"512d84b99c93d51729215de3d796390f762f74692306863e3f3bcb0090b399f4"}]}]}`,
+ tmplStr: `{"raw_transaction":"0701a8d30201010060015e7e8cf2b20c310f7a8197d598f04a04470eda4d59470661d124b688b507525a9dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c8afa0250101160014b6fd589b689b2e7a8772c5c0a855734851c2f72a010001013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086d8f02401160014b6fd589b689b2e7a8772c5c0a855734851c2f72a00667b2254797065223a3231302c2244617461223a2265794a6d62334a6e5a584a7a496a7062496e5a7a625446784d32316d625752324e6a52714d6e70684d4755326548646c64475a77634745304e326833633368325a7a6b7a5a6e5635655730695858303d227d","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"67e1a63e43dbd7148aa3ffe5a8e869ff5d89f687d1d29f6224a95bd0ce3b3eb61e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445","derivation_path":null}],"signatures":null},{"type":"data","value":"67e1a63e43dbd7148aa3ffe5a8e869ff5d89f687d1d29f6224a95bd0ce3b3eb6"}]}],"fee":100000000,"allow_additional_actions":false}`,
respWant: &EstimateTxGasResp{
TotalNeu: (flexibleGas + 2095) * consensus.VMGasRate,
},
--- /dev/null
+package api
+
+import (
+ "context"
+
+ dpos "github.com/vapor/consensus/consensus/dpos"
+)
+
+func (a *API) listDelegates(ctx context.Context) Response {
+ return NewSuccessResponse(dpos.GDpos.ListDelegates())
+}
+
+func (a *API) getDelegateVotes(ctx context.Context, ins struct {
+ DelegateAddress string `json:"delegate_address"`
+}) Response {
+ votes := map[string]uint64{"votes": dpos.GDpos.GetDelegateVotes(ins.DelegateAddress)}
+ return NewSuccessResponse(votes)
+}
+
+func (a *API) listVotedDelegates(ctx context.Context, ins struct {
+ Voter string `json:"voter"`
+}) Response {
+ delegates := make(map[string]string)
+ for _, delegate := range dpos.GDpos.GetVotedDelegates(ins.Voter) {
+ delegates[dpos.GDpos.GetDelegateName(delegate)] = delegate
+ }
+ return NewSuccessResponse(delegates)
+}
+
+func (a *API) listReceivedVotes(ctx context.Context, ins struct {
+ DelegateAddress string `json:"delegate_address"`
+}) Response {
+ return NewSuccessResponse(dpos.GDpos.GetDelegateVoters(ins.DelegateAddress))
+}
+
+func (a *API) getAddressBalance(ctx context.Context, ins struct {
+ Address string `json:"address"`
+}) Response {
+ return NewSuccessResponse(dpos.GDpos.GetAddressBalance(ins.Address))
+}
+++ /dev/null
-package api
-
-import (
- "context"
- "time"
-
- log "github.com/sirupsen/logrus"
- "github.com/vapor/account"
- "github.com/vapor/blockchain/pseudohsm"
- "github.com/vapor/blockchain/txbuilder"
- "github.com/vapor/config"
- "github.com/vapor/crypto/ed25519/chainkd"
- "github.com/vapor/protocol/bc"
-)
-
-func (a *API) registe(ctx context.Context, ins struct {
- DelegateAddress string `json:"delegate_address"`
- DelegateName string `json:"delegate_name"`
-}) Response {
-
-
-
- return NewSuccessResponse("")
-}
-
-func (a *API) dpos(ctx context.Context, ins struct {
- From string `json:"from"`
- To string `json:"to"`
- Fee uint64 `json:"fee"`
- Stake uint64 `json:"stake"`
- TxType uint32 `json:"tx_type"`
-}) Response {
- // 找到utxo
- var assetID bc.AssetID
- assetID.UnmarshalText([]byte("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
- // 生成dpos交易
- dpos := account.DopsAction{
- Accounts: a.wallet.AccountMgr,
- From: ins.From,
- To: ins.To,
- Fee: ins.Fee,
- TxType: ins.TxType,
- }
- dpos.Amount = ins.Stake
- dpos.AssetId = &assetID
- builder := txbuilder.NewBuilder(time.Now())
- if err := dpos.Build(ctx, builder); err != nil {
- return NewErrorResponse(err)
- }
-
- // 签名
- tmpl, _, err := builder.Build()
- if err != nil {
- return NewErrorResponse(err)
- }
- var xprv chainkd.XPrv
- xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
- if err := pseudohsm.SignWithKey(tmpl, xprv); err != nil {
- return NewErrorResponse(err)
- }
- log.Info("Sign Transaction complete.")
- log.Info(txbuilder.SignProgress(tmpl))
- //return NewSuccessResponse(&signTemplateResp{Tx: tmpl, SignComplete: txbuilder.SignProgress(tmpl)})
- // 提交
-
- if err := txbuilder.FinalizeTx(ctx, a.chain, tmpl.Transaction); err != nil {
- return NewErrorResponse(err)
- }
-
- log.WithField("tx_id", tmpl.Transaction.ID.String()).Info("submit single tx")
- return NewSuccessResponse(&submitTxResp{TxID: &tmpl.Transaction.ID})
-}
log "github.com/sirupsen/logrus"
+ "github.com/vapor/blockchain/pseudohsm"
"github.com/vapor/blockchain/txbuilder"
"github.com/vapor/common"
"github.com/vapor/consensus"
return NewSuccessResponse(&signTemplateResp{Tx: &x.Txs, SignComplete: txbuilder.SignProgress(&x.Txs)})
}
+func (a *API) signWithPriKey(ins struct {
+ Xprv string `json:"xprv"`
+ Tx txbuilder.Template `json:"transaction"`
+}) Response {
+ xprv := &chainkd.XPrv{}
+ if err := xprv.UnmarshalText([]byte(ins.Xprv)); err != nil {
+ return NewErrorResponse(err)
+ }
+ if err := pseudohsm.SignWithKey(&ins.Tx, *xprv); err != nil {
+ return NewErrorResponse(err)
+ }
+ log.Info("Sign Transaction complete.")
+ return NewSuccessResponse(&signTemplateResp{Tx: &ins.Tx, SignComplete: txbuilder.SignProgress(&ins.Tx)})
+}
+
type signTemplatesResp struct {
Tx []*txbuilder.Template `json:"transaction"`
SignComplete bool `json:"sign_complete"`
"retire": txbuilder.DecodeRetireAction,
"spend_account": a.wallet.AccountMgr.DecodeSpendAction,
"spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction,
- "dpos_address": a.wallet.AccountMgr.DecodeDposAction,
+ "dpos": a.wallet.AccountMgr.DecodeDposAction,
"ipfs_data": txbuilder.DecodeIpfsDataAction,
}
decoder, ok := decoders[action]
if !ok {
return false, errors.WithDetailf(ErrBadActionType, "no action type provided on action %d", i)
}
- if strings.HasPrefix(actionType, "dpos_address") {
+ if strings.HasPrefix(actionType, "dpos") {
dpos = true
}
if strings.HasPrefix(actionType, "spend") || actionType == "issue" {
"github.com/vapor/common"
"github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
+ "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/protocol"
}
func mockChain(testDB dbm.DB) (*protocol.Chain, error) {
+ var engine engine.Engine
+ switch config.CommonConfig.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
store := leveldb.NewStore(testDB)
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ chain, err := protocol.NewChain(store, txPool, engine)
if err != nil {
return nil, err
}
func mockNewRegistry(t *testing.T) *Registry {
config.CommonConfig = config.DefaultConfig()
consensus.SoloNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
dirPath, err := ioutil.TempDir(".", "")
if err != nil {
timeRange uint64
rollbacks []func()
callbacks []func() error
+ referenceData []byte
}
// AddInput add inputs of transactions
return nil
}
+func (b *TemplateBuilder) SetReferenceData(referenceData []byte) {
+ b.referenceData = referenceData
+}
+
// InputCount return number of input in the template builder
func (b *TemplateBuilder) InputCount() int {
return len(b.inputs)
tx.Inputs = append(tx.Inputs, in)
}
+ tx.ReferenceData = b.referenceData
+
tpl.Transaction = types.NewTx(*tx)
tpl.Fee = CalculateTxFee(tpl.Transaction)
return tpl, tx, nil
{
"consensus":{
- "dpos": {
+ "consensus_type": "dpos" ,
"period": 3,
- "epoch": 300,
- "maxSignersCount": 1,
- "minVoterBalance": 0,
- "genesisTimestamp": 1524549600,
+ "max_signers_count": 2,
+ "min_boter_balance": 10,
+ "genesis_timestamp": 1524549600,
"coinbase": "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep",
"xprv": "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445",
"signers": [
"vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
]
- }
}
}
\ No newline at end of file
chain_id = "solonet"
[p2p]
laddr = "tcp://0.0.0.0:56658"
-seeds = ""
+seeds = "127.0.0.1:56659"
}
type ConsensusConfig struct {
- Dpos *DposConfig `mapstructure:"dpos"`
+ Type string `mapstructure:"consensus_type"`
+ Period uint64 `json:"period"` // Number of seconds between blocks to enforce
+ MaxSignerCount uint64 `json:"max_signers_count"` // Max count of signers
+ MinVoterBalance uint64 `json:"min_boter_balance"` // Min voter balance to valid this vote
+ GenesisTimestamp uint64 `json:"genesis_timestamp"` // The LoopStartTime of first Block
+ Coinbase string `json:"coinbase"`
+ XPrv string `json:"xprv"`
+ SelfVoteSigners []string `json:"signers"` // Signers vote by themselves to seal the block, make sure the signer accounts are pre-funded
+ Signers []common.Address
}
type DposConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
- Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
MaxSignerCount uint64 `json:"max_signers_count"` // Max count of signers
MinVoterBalance uint64 `json:"min_boter_balance"` // Min voter balance to valid this vote
GenesisTimestamp uint64 `json:"genesis_timestamp"` // The LoopStartTime of first Block
func DefaultDposConfig() *DposConfig {
return &DposConfig{
Period: 1,
- Epoch: 300,
MaxSignerCount: 1,
MinVoterBalance: 0,
GenesisTimestamp: 1524549600,
}
func DefaultConsensusCOnfig() *ConsensusConfig {
- return &ConsensusConfig{Dpos: DefaultDposConfig()}
+ return &ConsensusConfig{
+ Type: "dpos",
+ Period: 1,
+ MaxSignerCount: 1,
+ MinVoterBalance: 0,
+ GenesisTimestamp: 1524549600}
}
//-----------------------------------------------------------------------------
"github.com/vapor/consensus"
"github.com/vapor/crypto/ed25519"
- "github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
"github.com/vapor/protocol/vm/vmutil"
fedpegScript, _ := vmutil.P2SPMultiSigProgram(fedpegPubkeys, len(fedpegPubkeys))
var buffer bytes.Buffer
- for _, address := range CommonConfig.Consensus.Dpos.Signers {
+ for _, address := range CommonConfig.Consensus.Signers {
redeemContract := address.ScriptAddress()
buffer.Write(redeemContract)
}
log.Panicf("fail on calc genesis tx merkel root")
}
- var xPrv chainkd.XPrv
- if CommonConfig.Consensus.Dpos.XPrv == "" {
- log.Panicf("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(CommonConfig.Consensus.Dpos.XPrv))
- b, _ := xPrv.XPub().MarshalText()
-
block := &types.Block{
BlockHeader: types.BlockHeader{
Version: 1,
TransactionsMerkleRoot: merkleRoot,
TransactionStatusHash: txStatusHash,
},
- Coinbase: b,
},
Transactions: []*types.Tx{tx},
}
if err != nil {
log.Panicf("fail on calc genesis tx merkel root")
}
-
- var xPrv chainkd.XPrv
- if CommonConfig.Consensus.Dpos.XPrv == "" {
- log.Panicf("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(CommonConfig.Consensus.Dpos.XPrv))
- b, _ := xPrv.XPub().MarshalText()
-
block := &types.Block{
BlockHeader: types.BlockHeader{
Version: 1,
TransactionsMerkleRoot: merkleRoot,
TransactionStatusHash: txStatusHash,
},
- Coinbase: b,
},
Transactions: []*types.Tx{tx},
}
log.Panicf("fail on calc genesis tx merkel root")
}
- var xPrv chainkd.XPrv
- if CommonConfig.Consensus.Dpos.XPrv == "" {
- log.Panicf("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(CommonConfig.Consensus.Dpos.XPrv))
- b, _ := xPrv.XPub().MarshalText()
-
block := &types.Block{
BlockHeader: types.BlockHeader{
Version: 1,
Height: 0,
- Timestamp: 1528945000,
+ Timestamp: CommonConfig.Consensus.GenesisTimestamp,
BlockCommitment: types.BlockCommitment{
TransactionsMerkleRoot: merkleRoot,
TransactionStatusHash: txStatusHash,
},
- Coinbase: b,
},
Transactions: []*types.Tx{tx},
}
import (
"github.com/vapor/chain"
+ "github.com/vapor/common"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
)
-// Engine is an algorithm agnostic consensus engine.
-type Engine interface {
-
- // VerifySeal checks whether the crypto seal on a header is valid according to
- // the consensus rules of the given engine.
- VerifySeal(c chain.Chain, header *types.BlockHeader) error
-
- // Prepare initializes the consensus fields of a block header according to the
- // rules of a particular engine. The changes are executed inline.
- Prepare(c chain.Chain, header *types.BlockHeader) error
+type AddressBalance struct {
+ Address string
+ Balance int64
+}
- // Finalize runs any post-transaction state modifications (e.g. block rewards)
- // and assembles the final block.
- // Note: The block header and state database might be updated to reflect any
- // consensus rules that happen at finalization (e.g. block rewards).
- Finalize(c chain.Chain, header *types.BlockHeader, txs []*bc.Tx) error
+type DelegateInterface interface {
+ ConsensusName() string
+}
- // Seal generates a new block for the given input block with the local miner's
- // seal place on top.
- Seal(c chain.Chain, block *types.Block) (*types.Block, error)
+// Engine is an algorithm agnostic consensus engine.
+type Engine interface {
+ Init(c chain.Chain, delegateNumber, intervalTime, blockHeight uint64, blockHash bc.Hash) error
+ Finish() error
+ IsMining(address common.Address, t uint64) (interface{}, error)
+ ProcessRegister(delegateAddress string, delegateName string, hash bc.Hash, height uint64) bool
+ ProcessVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool
+ ProcessCancelVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool
+ UpdateAddressBalance(addressBalance []AddressBalance)
+ CheckBlockHeader(header types.BlockHeader) error
+ CheckBlock(block types.Block, fIsCheckDelegateInfo bool) error
+ IsValidBlockCheckIrreversibleBlock(height uint64, hash bc.Hash) error
+ GetOldBlockHeight() uint64
+ GetOldBlockHash() bc.Hash
}
+++ /dev/null
-package consensus
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "math/rand"
- "path/filepath"
- "sync"
- "time"
-
- "github.com/vapor/crypto/ed25519/chainkd"
-
- "github.com/vapor/consensus"
-
- "github.com/vapor/chain"
- "github.com/vapor/common"
- "github.com/vapor/config"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
-)
-
-type Delegate struct {
- DelegateAddress string `json:"delegate_address"`
- Votes uint64 `json:"votes"`
-}
-
-type DelegateInfo struct {
- Delegates []Delegate `json:"delegates"`
-}
-
-//OP_FAIL PUBKEY SIG(block.time) DELEGATE_IDS
-func DelegateInfoToScript(delegateInfo DelegateInfo, xpub chainkd.XPub, h bc.Hash) {
-
-}
-
-//ScriptToDelegateInfo
-
-const maxConfirmBlockCount = 2
-
-type IrreversibleBlockInfo struct {
- heights []int64
- hashs []bc.Hash
- HeightHash map[int64]bc.Hash
-}
-
-func newIrreversibleBlockInfo() *IrreversibleBlockInfo {
- o := &IrreversibleBlockInfo{}
- for i := 0; i < maxConfirmBlockCount; i++ {
- o.heights = append(o.heights, -1)
- }
- return o
-}
-
-type DposType struct {
- c chain.Chain
- MaxDelegateNumber uint64
- BlockIntervalTime uint64
- DposStartHeight uint64
- DposStartTime uint64
- cSuperForgerAddress common.Address
- irreversibleBlockFileName string
- cIrreversibleBlockInfo IrreversibleBlockInfo
- lockIrreversibleBlockInfo sync.Mutex
-}
-
-var GDpos = &DposType{}
-
-func init() {
- GDpos.irreversibleBlockFileName = filepath.Join(config.DefaultDataDir(), "dpos", "irreversible_block.dat")
- GDpos.ReadIrreversibleBlockInfo(&GDpos.cIrreversibleBlockInfo)
-
-}
-
-func (d *DposType) ReadIrreversibleBlockInfo(info *IrreversibleBlockInfo) error {
- return nil
-}
-
-func (d *DposType) IsMining(cDelegateInfo *DelegateInfo, address common.Address, t uint64) error {
-
- header := d.c.BestBlockHeader()
- currentLoopIndex := d.GetLoopIndex(t)
- currentDelegateIndex := d.GetDelegateIndex(t)
- prevLoopIndex := d.GetLoopIndex(header.Timestamp)
- prevDelegateIndex := d.GetDelegateIndex(header.Timestamp)
-
- if currentLoopIndex > prevLoopIndex {
- *cDelegateInfo = d.GetNextDelegates(t)
- if cDelegateInfo.Delegates[currentLoopIndex].DelegateAddress == address.EncodeAddress() {
- return nil
- }
- return errors.New("Is not the current mining node")
- } else if currentLoopIndex == prevLoopIndex && currentDelegateIndex > prevDelegateIndex {
- //currentDelegateInfo := DelegateInfo{}
- currentDelegateInfo, err := d.GetBlockDelegates(header)
- if err != nil {
- return err
- }
- if currentDelegateIndex+1 > uint64(len(currentDelegateInfo.Delegates)) {
- return errors.New("Out of the block node list")
- } else if currentDelegateInfo.Delegates[currentDelegateIndex].DelegateAddress == address.EncodeAddress() {
- return nil
- } else {
- return errors.New("Is not the current mining node")
- }
- } else {
- return errors.New("Time anomaly")
- }
-}
-
-func (d *DposType) GetLoopIndex(time uint64) uint64 {
- if time < d.DposStartTime {
- return 0
- }
-
- return (time - d.DposStartTime) / (d.MaxDelegateNumber * d.BlockIntervalTime)
-}
-
-func (d *DposType) GetDelegateIndex(time uint64) uint64 {
- if time < d.DposStartTime {
- return 0
- }
-
- return (time - d.DposStartTime) % (d.MaxDelegateNumber * d.BlockIntervalTime) / d.BlockIntervalTime
-}
-
-func (d *DposType) GetNextDelegates(t uint64) DelegateInfo {
- delegates := DposVote.GetTopDelegateInfo(consensus.MinHoldBalance, d.MaxDelegateNumber-1)
- delegate := Delegate{
- DelegateAddress: d.cSuperForgerAddress.EncodeAddress(),
- Votes: 7,
- }
- delegates = append(delegates, delegate)
- delegateInfo := DelegateInfo{}
- delegateInfo.Delegates = SortDelegate(delegates, t)
- return delegateInfo
-}
-
-func (d *DposType) GetBlockDelegates(header *types.BlockHeader) (*DelegateInfo, error) {
- loopIndex := d.GetLoopIndex(header.Timestamp)
- for {
- preHeader, err := d.c.GetHeaderByHash(&header.PreviousBlockHash)
- if err != nil {
- return nil, err
- }
- if header.Height == d.DposStartHeight || d.GetLoopIndex(preHeader.Timestamp) < loopIndex {
- block, err := d.c.GetBlockByHeight(header.Height)
- if err != nil {
- return nil, err
- }
- delegateInfo, err := d.GetBlockDelegate(block)
- if err != nil {
- return nil, err
- }
- return delegateInfo, nil
- }
- header = preHeader
- }
-}
-
-func (d *DposType) GetBlockDelegate(block *types.Block) (*DelegateInfo, error) {
- tx := block.Transactions[0]
- var delegate TypedData
- if len(tx.TxData.Inputs) == 1 && tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType {
- if err := json.Unmarshal(tx.TxData.ReferenceData, delegate); err != nil {
- return nil, err
- }
- if delegateInfo, ok := delegate.(*DelegateInfoList); ok {
- return &delegateInfo.Delegate, nil
- }
- }
- return nil, errors.New("The first transaction is not a coinbase transaction")
-}
-
-func (d *DposType) CheckCoinbase(tx types.TxData, t uint64, Height uint64) error {
-
- return nil
-}
-
-func (d *DposType) CheckBlockHeader(header types.BlockHeader) error {
- blockT := time.Unix(int64(header.Timestamp), 0)
-
- if blockT.Sub(time.Now()).Seconds() > 3 {
- return errors.New("block time is error")
- }
-
- return nil
-}
-
-func (d *DposType) CheckBlock(block types.Block, fIsCheckDelegateInfo bool) error {
- blockT := time.Unix(int64(block.Timestamp), 0)
-
- if blockT.Sub(time.Now()).Seconds() > 3 {
- return errors.New("block time is error")
- }
-
- if err := d.CheckCoinbase(block.Transactions[0].TxData, block.Timestamp, block.Height); err != nil {
- return err
- }
-
- preBlock, err := d.c.GetBlockByHash(&block.PreviousBlockHash)
- if err != nil {
- return err
- }
-
- currentLoopIndex := d.GetLoopIndex(block.Timestamp)
- currentDelegateIndex := d.GetDelegateIndex(block.Timestamp)
- prevLoopIndex := d.GetLoopIndex(preBlock.Timestamp)
- prevDelegateIndex := d.GetDelegateIndex(preBlock.Timestamp)
-
- delegateInfo := &DelegateInfo{}
-
- if currentLoopIndex < prevLoopIndex {
- return errors.New("Block time exception")
- } else if currentLoopIndex > prevLoopIndex {
- if fIsCheckDelegateInfo {
- if err := d.CheckBlockDelegate(block); err != nil {
- return err
- }
- d.ProcessIrreversibleBlock(block.Height, block.Hash())
- }
- delegateInfo, err = d.GetBlockDelegate(&block)
- if err != nil {
- return err
- }
- } else {
- if currentDelegateIndex < prevDelegateIndex {
- return errors.New("Block time exception")
- }
-
- delegateInfo, err = d.GetBlockDelegates(&preBlock.BlockHeader)
- if err != nil {
- return err
- }
- }
-
- delegateAddress := d.getBlockForgerAddress(block)
- if currentDelegateIndex < uint64(len(delegateInfo.Delegates)) &&
- delegateInfo.Delegates[currentDelegateIndex].DelegateAddress == delegateAddress.EncodeAddress() {
- return nil
- }
- h := block.Hash()
- return fmt.Errorf("CheckBlock GetDelegateID blockhash:%s error", h.String())
-}
-
-func (d *DposType) CheckBlockDelegate(block types.Block) error {
- return nil
-}
-
-func (d *DposType) ProcessIrreversibleBlock(height uint64, hash bc.Hash) {
-
-}
-
-func (d *DposType) getBlockForgerAddress(block types.Block) common.Address {
- tx := block.Transactions[0].TxData
-
- if len(tx.Inputs) == 1 && tx.Inputs[0].InputType() == types.CoinbaseInputType {
- address, err := common.NewAddressWitnessPubKeyHash(tx.Outputs[0].ControlProgram[2:], &consensus.ActiveNetParams)
- if err != nil {
- address, err := common.NewAddressWitnessScriptHash(tx.Outputs[0].ControlProgram[2:], &consensus.ActiveNetParams)
- if err != nil {
- return nil
- }
- return address
- }
- return address
- }
-
- return nil
-}
-
-func (d *DposType) IsValidBlockCheckIrreversibleBlock(height uint64, hash bc.Hash) error {
- d.lockIrreversibleBlockInfo.Lock()
- defer d.lockIrreversibleBlockInfo.Unlock()
-
- if h, ok := d.cIrreversibleBlockInfo.HeightHash[int64(height)]; ok {
- if h != hash {
- return fmt.Errorf("invalid block[%d:%s]", height, hash.String())
- }
- }
-
- return nil
-}
-
-func SortDelegate(delegates []Delegate, t uint64) []Delegate {
- var result []Delegate
- r := getRand(uint64(len(delegates)), int64(t))
- for _, i := range r {
- result = append(result, delegates[i])
- }
- return result
-}
-
-func getRand(num uint64, seed int64) []uint64 {
- rand.Seed(seed)
- var r []uint64
- s := make(map[uint64]bool)
- for {
- v := rand.Uint64()
- v %= num
- if _, ok := s[v]; ok {
- continue
- }
- s[v] = true
- r = append(r, v)
- if uint64(len(r)) >= num {
- break
- }
- }
-
- return r
-}
+++ /dev/null
-package dpos
-
-import (
- "encoding/json"
- "strconv"
- "strings"
-
- log "github.com/sirupsen/logrus"
- "github.com/vapor/chain"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
-)
-
-const (
- /*
- * vapor:version:category:action/data
- */
- vaporPrefix = "vapor"
- vaporVersion = "1"
- vaporCategoryEvent = "event"
- vaporCategoryLog = "oplog"
- vaporCategorySC = "sc"
- vaporEventVote = "vote"
- vaporEventConfirm = "confirm"
- vaporEventPorposal = "proposal"
- vaporEventDeclare = "declare"
-
- vaporMinSplitLen = 3
- posPrefix = 0
- posVersion = 1
- posCategory = 2
- posEventVote = 3
- posEventConfirm = 3
- posEventProposal = 3
- posEventDeclare = 3
- posEventConfirmNumber = 4
-
- /*
- * proposal type
- */
- proposalTypeCandidateAdd = 1
- proposalTypeCandidateRemove = 2
- proposalTypeMinerRewardDistributionModify = 3 // count in one thousand
-
- /*
- * proposal related
- */
- maxValidationLoopCnt = 123500 // About one month if seal each block per second & 21 super nodes
- minValidationLoopCnt = 12350 // About three days if seal each block per second & 21 super nodes
- defaultValidationLoopCnt = 30875 // About one week if seal each block per second & 21 super nodes
-)
-
-// Vote :
-// vote come from custom tx which data like "vapor:1:event:vote"
-// Sender of tx is Voter, the tx.to is Candidate
-// Stake is the balance of Voter when create this vote
-type Vote struct {
- Voter string `json:"Voter"`
- Candidate string `json:"Candidate"`
- Stake uint64 `json:"Stake"`
-}
-
-// Confirmation :
-// confirmation come from custom tx which data like "vapor:1:event:confirm:123"
-// 123 is the block number be confirmed
-// Sender of tx is Signer only if the signer in the SignerQueue for block number 123
-type Confirmation struct {
- Signer string `json:"signer"`
- BlockNumber uint64 `json:"block_number"`
-}
-
-// Proposal :
-// proposal come from custom tx which data like "vapor:1:event:proposal:candidate:add:address" or "vapor:1:event:proposal:percentage:60"
-// proposal only come from the current candidates
-// not only candidate add/remove , current signer can proposal for params modify like percentage of reward distribution ...
-type Proposal struct {
- Hash bc.Hash `json:"hash"` // tx hash
- ValidationLoopCnt uint64 `json:"ValidationLoopCnt"` // validation block number length of this proposal from the received block number
- ImplementNumber uint64 `json:"ImplementNumber"` // block number to implement modification in this proposal
- ProposalType uint64 `json:"ProposalType"` // type of proposal 1 - add candidate 2 - remove candidate ...
- Proposer string `json:"Proposer"` //
- Candidate string `json:"Candidate"`
- MinerRewardPerThousand uint64 `json:"MinerRewardPerThousand"`
- Declares []*Declare `json:"Declares"` // Declare this proposal received
- ReceivedNumber uint64 `json:"ReceivedNumber"` // block number of proposal received
-}
-
-func (p *Proposal) copy() *Proposal {
- cpy := &Proposal{
- Hash: p.Hash,
- ValidationLoopCnt: p.ValidationLoopCnt,
- ImplementNumber: p.ImplementNumber,
- ProposalType: p.ProposalType,
- Proposer: p.Proposer,
- Candidate: p.Candidate,
- MinerRewardPerThousand: p.MinerRewardPerThousand,
- Declares: make([]*Declare, len(p.Declares)),
- ReceivedNumber: p.ReceivedNumber,
- }
-
- copy(cpy.Declares, p.Declares)
- return cpy
-}
-
-// Declare :
-// declare come from custom tx which data like "vapor:1:event:declare:hash:yes"
-// proposal only come from the current candidates
-// hash is the hash of proposal tx
-type Declare struct {
- ProposalHash bc.Hash `json:"ProposalHash"`
- Declarer string `json:"Declarer"`
- Decision bool `json:"Decision"`
-}
-
-// HeaderExtra is the struct of info in header.Extra[extraVanity:len(header.extra)-extraSeal]
-type HeaderExtra struct {
- CurrentBlockConfirmations []Confirmation `json:"current_block_confirmations"`
- CurrentBlockVotes []Vote `json:"CurrentBlockVotes"`
- CurrentBlockProposals []Proposal `json:"CurrentBlockProposals"`
- CurrentBlockDeclares []Declare `json:"CurrentBlockDeclares"`
- ModifyPredecessorVotes []Vote `json:"ModifyPredecessorVotes"`
- LoopStartTime uint64 `json:"LoopStartTime"`
- SignerQueue []string `json:"SignerQueue"`
- SignerMissing []string `json:"SignerMissing"`
- ConfirmedBlockNumber uint64 `json:"ConfirmedBlockNumber"`
-}
-
-// Calculate Votes from transaction in this block, write into header.Extra
-func (d *Dpos) processCustomTx(headerExtra HeaderExtra, c chain.Chain, header *types.BlockHeader, txs []*bc.Tx) (HeaderExtra, error) {
-
- var (
- snap *Snapshot
- err error
- height uint64
- )
- height = header.Height
- if height > 1 {
- snap, err = d.snapshot(c, height-1, header.PreviousBlockHash, nil, nil, defaultLoopCntRecalculateSigners)
- if err != nil {
- return headerExtra, err
- }
- }
-
- for _, tx := range txs {
- var (
- from string
- to string
- )
- dpos := new(bc.Dpos)
- stake := uint64(0)
- for _, value := range tx.Entries {
- switch d := value.(type) {
- case *bc.Dpos:
- from = d.From
- to = d.To
- dpos = d
- stake = d.Stake
- default:
- continue
- }
-
- if len(dpos.Data) >= len(vaporPrefix) {
- txData := dpos.Data
- txDataInfo := strings.Split(txData, ":")
- if len(txDataInfo) >= vaporMinSplitLen && txDataInfo[posPrefix] == vaporPrefix && txDataInfo[posVersion] == vaporVersion {
- switch txDataInfo[posCategory] {
- case vaporCategoryEvent:
- if len(txDataInfo) > vaporMinSplitLen {
- if txDataInfo[posEventVote] == vaporEventVote && (!candidateNeedPD || snap.isCandidate(to)) {
- headerExtra.CurrentBlockVotes = d.processEventVote(headerExtra.CurrentBlockVotes, stake, from, to)
- } else if txDataInfo[posEventConfirm] == vaporEventConfirm {
- headerExtra.CurrentBlockConfirmations = d.processEventConfirm(headerExtra.CurrentBlockConfirmations, c, txDataInfo, height, tx, from)
- } else if txDataInfo[posEventProposal] == vaporEventPorposal && snap.isCandidate(from) {
- headerExtra.CurrentBlockProposals = d.processEventProposal(headerExtra.CurrentBlockProposals, txDataInfo, tx, from)
- } else if txDataInfo[posEventDeclare] == vaporEventDeclare && snap.isCandidate(from) {
- headerExtra.CurrentBlockDeclares = d.processEventDeclare(headerExtra.CurrentBlockDeclares, txDataInfo, tx, from)
-
- }
- } else {
- // todo : something wrong, leave this transaction to process as normal transaction
- }
-
- case vaporCategoryLog:
- // todo :
- case vaporCategorySC:
- // todo :
- }
- }
- }
- }
- }
-
- return headerExtra, nil
-}
-
-func (d *Dpos) processEventProposal(currentBlockProposals []Proposal, txDataInfo []string, tx *bc.Tx, proposer string) []Proposal {
- proposal := Proposal{
- Hash: tx.ID,
- ValidationLoopCnt: defaultValidationLoopCnt,
- ImplementNumber: uint64(1),
- ProposalType: proposalTypeCandidateAdd,
- Proposer: proposer,
- MinerRewardPerThousand: minerRewardPerThousand,
- Declares: []*Declare{},
- ReceivedNumber: uint64(0),
- }
-
- for i := 0; i < len(txDataInfo[posEventProposal+1:])/2; i++ {
- k, v := txDataInfo[posEventProposal+1+i*2], txDataInfo[posEventProposal+2+i*2]
- switch k {
- case "vlcnt":
- // If vlcnt is missing then user default value, but if the vlcnt is beyond the min/max value then ignore this proposal
- if validationLoopCnt, err := strconv.Atoi(v); err != nil || validationLoopCnt < minValidationLoopCnt || validationLoopCnt > maxValidationLoopCnt {
- return currentBlockProposals
- } else {
- proposal.ValidationLoopCnt = uint64(validationLoopCnt)
- }
- case "implement_number":
- if implementNumber, err := strconv.Atoi(v); err != nil || implementNumber <= 0 {
- return currentBlockProposals
- } else {
- proposal.ImplementNumber = uint64(implementNumber)
- }
- case "proposal_type":
- if proposalType, err := strconv.Atoi(v); err != nil || (proposalType != proposalTypeCandidateAdd && proposalType != proposalTypeCandidateRemove && proposalType != proposalTypeMinerRewardDistributionModify) {
- return currentBlockProposals
- } else {
- proposal.ProposalType = uint64(proposalType)
- }
- case "candidate":
- // not check here
- //proposal.Candidate.UnmarshalText([]byte(v))
- /*
- address, err := common.DecodeAddress(v, &consensus.ActiveNetParams)
- if err != nil {
- return currentBlockProposals
- }
- */
- proposal.Candidate = v
- case "mrpt":
- // miner reward per thousand
- if mrpt, err := strconv.Atoi(v); err != nil || mrpt < 0 || mrpt > 1000 {
- return currentBlockProposals
- } else {
- proposal.MinerRewardPerThousand = uint64(mrpt)
- }
-
- }
- }
-
- return append(currentBlockProposals, proposal)
-}
-
-func (d *Dpos) processEventDeclare(currentBlockDeclares []Declare, txDataInfo []string, tx *bc.Tx, declarer string) []Declare {
- declare := Declare{
- ProposalHash: bc.Hash{},
- Declarer: declarer,
- Decision: true,
- }
-
- for i := 0; i < len(txDataInfo[posEventDeclare+1:])/2; i++ {
- k, v := txDataInfo[posEventDeclare+1+i*2], txDataInfo[posEventDeclare+2+i*2]
- switch k {
- case "hash":
- declare.ProposalHash.UnmarshalText([]byte(v))
- case "decision":
- if v == "yes" {
- declare.Decision = true
- } else if v == "no" {
- declare.Decision = false
- } else {
- return currentBlockDeclares
- }
- }
- }
-
- return append(currentBlockDeclares, declare)
-}
-
-func (d *Dpos) processEventVote(currentBlockVotes []Vote, stake uint64, voter, to string) []Vote {
- if stake >= d.config.MinVoterBalance {
- currentBlockVotes = append(currentBlockVotes, Vote{
- Voter: voter,
- Candidate: to,
- Stake: stake,
- })
- }
- return currentBlockVotes
-}
-
-func (d *Dpos) processEventConfirm(currentBlockConfirmations []Confirmation, c chain.Chain, txDataInfo []string, number uint64, tx *bc.Tx, confirmer string) []Confirmation {
- if len(txDataInfo) > posEventConfirmNumber {
- confirmedBlockNumber, err := strconv.Atoi(txDataInfo[posEventConfirmNumber])
- if err != nil || number-uint64(confirmedBlockNumber) > d.config.MaxSignerCount || number-uint64(confirmedBlockNumber) < 0 {
- return currentBlockConfirmations
- }
- confirmedHeader, err := c.GetBlockByHeight(uint64(confirmedBlockNumber))
- if confirmedHeader == nil {
- log.Info("Fail to get confirmedHeader")
- return currentBlockConfirmations
- }
- confirmedHeaderExtra := HeaderExtra{}
- if extraVanity+extraSeal > len(confirmedHeader.Extra) {
- return currentBlockConfirmations
- }
- if err := json.Unmarshal(confirmedHeader.Extra[extraVanity:len(confirmedHeader.Extra)-extraSeal], &confirmedHeaderExtra); err != nil {
- log.Info("Fail to decode parent header", "err", err)
- return currentBlockConfirmations
- }
- for _, s := range confirmedHeaderExtra.SignerQueue {
- if s == confirmer {
- currentBlockConfirmations = append(currentBlockConfirmations, Confirmation{
- Signer: confirmer,
- BlockNumber: uint64(confirmedBlockNumber),
- })
- break
- }
- }
- }
-
- return currentBlockConfirmations
-}
package dpos
import (
- "bytes"
+ "bufio"
+ "encoding/binary"
"encoding/json"
"errors"
- "math/big"
+ "fmt"
+ "io"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
"sync"
"time"
- lru "github.com/hashicorp/golang-lru"
- log "github.com/sirupsen/logrus"
"github.com/vapor/chain"
"github.com/vapor/common"
"github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
"github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519/chainkd"
- "github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
- "github.com/vapor/protocol/vm/vmutil"
+ "github.com/vapor/protocol/vm"
)
-const (
- inMemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
- inMemorySignatures = 4096 // Number of recent block signatures to keep in memory
- secondsPerYear = 365 * 24 * 3600 // Number of seconds for one year
- checkpointInterval = 360 // About N hours if config.period is N
- module = "dpos"
-)
+type Delegate struct {
+ DelegateAddress string `json:"delegate_address"`
+ Votes uint64 `json:"votes"`
+}
-//delegated-proof-of-stake protocol constants.
-var (
- SignerBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block first year
- defaultEpochLength = uint64(3000000) // Default number of blocks after which vote's period of validity
- defaultBlockPeriod = uint64(3) // Default minimum difference between two consecutive block's timestamps
- defaultMaxSignerCount = uint64(21) //
- //defaultMinVoterBalance = new(big.Int).Mul(big.NewInt(10000), big.NewInt(1e+18))
- defaultMinVoterBalance = uint64(0)
- extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
- extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
- defaultDifficulty = big.NewInt(1) // Default difficulty
- defaultLoopCntRecalculateSigners = uint64(10) // Default loop count to recreate signers from top tally
- minerRewardPerThousand = uint64(618) // Default reward for miner in each block from block reward (618/1000)
- candidateNeedPD = false // is new candidate need Proposal & Declare process
-)
+type DelegateWrapper struct {
+ delegate []Delegate
+ by func(p, q *Delegate) bool
+}
-var (
- // errUnknownBlock is returned when the list of signers is requested for a block
- // that is not part of the local blockchain.
- errUnknownBlock = errors.New("unknown block")
+func (dw DelegateWrapper) Len() int {
+ return len(dw.delegate)
+}
+func (dw DelegateWrapper) Swap(i, j int) {
+ dw.delegate[i], dw.delegate[j] = dw.delegate[j], dw.delegate[i]
+}
+func (dw DelegateWrapper) Less(i, j int) bool {
+ return dw.by(&dw.delegate[i], &dw.delegate[j])
+}
- // errMissingVanity is returned if a block's extra-data section is shorter than
- // 32 bytes, which is required to store the signer vanity.
- errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
+type DelegateInfo struct {
+ Delegates []Delegate `json:"delegates"`
+}
- // errMissingSignature is returned if a block's extra-data section doesn't seem
- // to contain a 65 byte secp256k1 signature.
- errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
+func (d *DelegateInfo) ConsensusName() string {
+ return "dpos"
+}
- // errInvalidMixDigest is returned if a block's mix digest is non-zero.
- errInvalidMixDigest = errors.New("non-zero mix digest")
+const maxConfirmBlockCount = 2
- // errInvalidUncleHash is returned if a block contains an non-empty uncle list.
- errInvalidUncleHash = errors.New("non empty uncle hash")
+type IrreversibleBlockInfo struct {
+ heights []int64
+ hashs []bc.Hash
+ HeightHash map[int64]bc.Hash
+}
- // ErrInvalidTimestamp is returned if the timestamp of a block is lower than
- // the previous block's timestamp + the minimum block period.
- ErrInvalidTimestamp = errors.New("invalid timestamp")
+func newIrreversibleBlockInfo() *IrreversibleBlockInfo {
+ o := &IrreversibleBlockInfo{}
+ for i := 0; i < maxConfirmBlockCount; i++ {
+ o.heights = append(o.heights, -1)
+ o.hashs = append(o.hashs, bc.Hash{})
+ }
+ o.HeightHash = make(map[int64]bc.Hash)
+ return o
+}
- // errInvalidVotingChain is returned if an authorization list is attempted to
- // be modified via out-of-range or non-contiguous headers.
- errInvalidVotingChain = errors.New("invalid voting chain")
+type DposType struct {
+ c chain.Chain
+ vote *Vote
+ MaxDelegateNumber uint64
+ BlockIntervalTime uint64
+ DposStartHeight uint64
+ DposStartTime uint64
+ superForgerAddress common.Address
+ irreversibleBlockFileName string
+ irreversibleBlockInfo IrreversibleBlockInfo
+ lockIrreversibleBlockInfo sync.Mutex
+ maxIrreversibleCount int
+ firstIrreversibleThreshold uint64
+ secondIrreversibleThreshold uint64
+}
- // errUnauthorized is returned if a header is signed by a non-authorized entity.
- errUnauthorized = errors.New("unauthorized")
+var GDpos = &DposType{
+ maxIrreversibleCount: 10000,
+ firstIrreversibleThreshold: 90,
+ secondIrreversibleThreshold: 67,
+}
- // errPunishedMissing is returned if a header calculate punished signer is wrong.
- errPunishedMissing = errors.New("punished signer missing")
+func (d *DposType) Init(c chain.Chain, delegateNumber, intervalTime, blockHeight uint64, blockHash bc.Hash) error {
+ d.c = c
+ vote, err := newVote(blockHeight, blockHash)
+ if err != nil {
+ return err
+ }
+ d.vote = vote
+ d.MaxDelegateNumber = delegateNumber
+ d.BlockIntervalTime = intervalTime
+ d.DposStartHeight = 0
+ address, _ := common.DecodeAddress("vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep", &consensus.ActiveNetParams)
+ d.superForgerAddress = address
- // errWaitTransactions is returned if an empty block is attempted to be sealed
- // on an instant chain (0 second period). It's important to refuse these as the
- // block reward is zero, so an empty block just bloats the chain... fast.
- errWaitTransactions = errors.New("waiting for transactions")
+ GDpos.irreversibleBlockFileName = filepath.Join(config.CommonConfig.RootDir, "dpos", "irreversible_block.dat")
+ GDpos.irreversibleBlockInfo = *newIrreversibleBlockInfo()
+ if err := GDpos.ReadIrreversibleBlockInfo(&GDpos.irreversibleBlockInfo); err != nil {
+ return err
+ }
- // errUnclesNotAllowed is returned if uncles exists
- errUnclesNotAllowed = errors.New("uncles not allowed")
+ header, _ := c.GetHeaderByHeight(d.DposStartHeight)
+ d.setStartTime(header.Timestamp)
+ return nil
+}
- // errCreateSignerQueueNotAllowed is returned if called in (block number + 1) % maxSignerCount != 0
- errCreateSignerQueueNotAllowed = errors.New("create signer queue not allowed")
+func (d *DposType) setStartTime(t uint64) {
+ d.DposStartTime = t
+}
- // errInvalidSignerQueue is returned if verify SignerQueue fail
- errInvalidSignerQueue = errors.New("invalid signer queue")
+func (d *DposType) IsMining(address common.Address, t uint64) (interface{}, error) {
+
+ header := d.c.BestBlockHeader()
+ currentLoopIndex := d.GetLoopIndex(t)
+ currentDelegateIndex := d.GetDelegateIndex(t)
+ prevLoopIndex := d.GetLoopIndex(header.Timestamp)
+ prevDelegateIndex := d.GetDelegateIndex(header.Timestamp)
+ if currentLoopIndex > prevLoopIndex {
+ delegateInfo := d.GetNextDelegates(t)
+ cDelegateInfo := delegateInfo.(*DelegateInfo)
+ if cDelegateInfo.Delegates[currentDelegateIndex].DelegateAddress == address.EncodeAddress() {
+ return delegateInfo, nil
+ }
+ return nil, errors.New("Is not the current mining node")
+ } else if currentLoopIndex == prevLoopIndex && currentDelegateIndex > prevDelegateIndex {
+ currentDelegateInfo, err := d.GetBlockDelegates(header)
+ if err != nil {
+ return nil, err
+ }
+ if currentDelegateIndex+1 > uint64(len(currentDelegateInfo.Delegates)) {
+ return nil, errors.New("Out of the block node list")
+ } else if currentDelegateInfo.Delegates[currentDelegateIndex].DelegateAddress == address.EncodeAddress() {
+ return nil, nil
+ } else {
+ return nil, errors.New("Is not the current mining node")
+ }
+ } else {
+ return nil, errors.New("Time anomaly")
+ }
+}
- // errSignerQueueEmpty is returned if no signer when calculate
- errSignerQueueEmpty = errors.New("signer queue is empty")
-)
+func (d *DposType) ProcessRegister(delegateAddress string, delegateName string, hash bc.Hash, height uint64) bool {
+ return d.vote.ProcessRegister(delegateAddress, delegateName, hash, height)
+}
-type Dpos struct {
- config *config.DposConfig // Consensus engine configuration parameters
- store protocol.Store // Database to store and retrieve snapshot checkpoints
- recents *lru.ARCCache // Snapshots for recent block to speed up reorgs
- signatures *lru.ARCCache // Signatures of recent blocks to speed up mining
- signer string // Ethereum address of the signing key
- lock sync.RWMutex // Protects the signer fields
- lcsc uint64 // Last confirmed side chain
-}
-
-//
-func ecrecover(header *types.BlockHeader, sigcache *lru.ARCCache, c chain.Chain) (string, error) {
- xpub := &chainkd.XPub{}
- xpub.UnmarshalText(header.Coinbase)
- derivedPK := xpub.PublicKey()
- pubHash := crypto.Ripemd160(derivedPK)
- address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
- if err != nil {
- return "", err
- }
+func (d *DposType) ProcessVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
+ return d.vote.ProcessVote(voterAddress, delegates, hash, height)
+}
- return address.EncodeAddress(), nil
+func (d *DposType) ProcessCancelVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
+ return d.vote.ProcessCancelVote(voterAddress, delegates, hash, height)
}
-//
-func New(config *config.DposConfig, store protocol.Store) *Dpos {
- conf := *config
- if conf.Epoch == 0 {
- conf.Epoch = defaultEpochLength
- }
- if conf.Period == 0 {
- conf.Period = defaultBlockPeriod
- }
- if conf.MaxSignerCount == 0 {
- conf.MaxSignerCount = defaultMaxSignerCount
+func (d *DposType) UpdateAddressBalance(addressBalance []engine.AddressBalance) {
+ d.vote.UpdateAddressBalance(addressBalance)
+}
+
+func (d *DposType) GetLoopIndex(time uint64) uint64 {
+ if time < d.DposStartTime {
+ return 0
}
- if conf.MinVoterBalance == 0 {
- conf.MinVoterBalance = defaultMinVoterBalance
+ return (time - d.DposStartTime) / (d.MaxDelegateNumber * d.BlockIntervalTime)
+}
+
+func (d *DposType) GetDelegateIndex(time uint64) uint64 {
+ if time < d.DposStartTime {
+ return 0
}
- // Allocate the snapshot caches and create the engine
- recents, _ := lru.NewARC(inMemorySnapshots)
- signatures, _ := lru.NewARC(inMemorySignatures)
- return &Dpos{
- config: &conf,
- store: store,
- recents: recents,
- signatures: signatures,
+ return (time - d.DposStartTime) % (d.MaxDelegateNumber * d.BlockIntervalTime) / d.BlockIntervalTime
+}
+
+func (d *DposType) GetNextDelegates(t uint64) interface{} {
+ delegates := d.vote.GetTopDelegateInfo(config.CommonConfig.Consensus.MinVoterBalance, d.MaxDelegateNumber-1)
+ delegate := Delegate{
+ DelegateAddress: d.superForgerAddress.EncodeAddress(),
+ Votes: 7,
}
+ delegates = append(delegates, delegate)
+ delegateInfo := DelegateInfo{}
+ delegateInfo.Delegates = SortDelegate(delegates, t)
+ return &delegateInfo
}
-// Authorize injects a private key into the consensus engine to mint new blocks with.
-func (d *Dpos) Authorize(signer string) {
- d.lock.Lock()
- defer d.lock.Unlock()
- d.signer = signer
+func (d *DposType) GetBlockDelegates(header *types.BlockHeader) (*DelegateInfo, error) {
+ loopIndex := d.GetLoopIndex(header.Timestamp)
+ for {
+ preHeader, err := d.c.GetHeaderByHash(&header.PreviousBlockHash)
+ if err != nil {
+ return nil, err
+ }
+ if header.Height == d.DposStartHeight || d.GetLoopIndex(preHeader.Timestamp) < loopIndex {
+ block, err := d.c.GetBlockByHeight(header.Height)
+ if err != nil {
+ return nil, err
+ }
+ delegateInfo, err := d.GetBlockDelegate(block)
+ if err != nil {
+ return nil, err
+ }
+ return delegateInfo, nil
+ }
+ header = preHeader
+ }
}
-func (d *Dpos) VerifySeal(c chain.Chain, header *types.BlockHeader) error {
- return d.verifyCascadingFields(c, header, nil)
+func (d *DposType) GetBlockDelegate(block *types.Block) (*DelegateInfo, error) {
+ tx := block.Transactions[0]
+ if len(tx.TxData.Inputs) == 1 && tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType {
+ msg := &DposMsg{}
+ if err := json.Unmarshal(tx.TxData.ReferenceData, msg); err != nil {
+ return nil, err
+ }
+ if msg.Type == vm.OP_DELEGATE {
+ delegateInfo := &DelegateInfoList{}
+ if err := json.Unmarshal(msg.Data, delegateInfo); err != nil {
+ return nil, err
+ }
+ return &delegateInfo.Delegate, nil
+ }
+
+ }
+ return nil, errors.New("The first transaction is not a coinbase transaction")
}
-func (d *Dpos) verifyCascadingFields(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
- // The genesis block is the always valid dead-end
- height := header.Height
- if height == 0 {
- return nil
+func (d *DposType) CheckCoinbase(tx types.TxData, t uint64, Height uint64) error {
+ msg := &DposMsg{}
+ if err := json.Unmarshal(tx.ReferenceData, msg); err != nil {
+ return err
}
+ if msg.Type == vm.OP_DELEGATE {
+ delegateInfo := &DelegateInfoList{}
+ if err := json.Unmarshal(msg.Data, delegateInfo); err != nil {
+ return err
+ }
+ buf := [8]byte{}
+ binary.LittleEndian.PutUint64(buf[:], t)
- var (
- parent *types.BlockHeader
- err error
- )
+ if !delegateInfo.Xpub.Verify(buf[:], delegateInfo.SigTime) {
+ return errors.New("CheckBlock CheckCoinbase: Verification signature error")
+ }
+ var (
+ address common.Address
+ err error
+ )
+ address, err = common.NewAddressWitnessPubKeyHash(tx.Outputs[0].ControlProgram[2:], &consensus.ActiveNetParams)
+ if err != nil {
+ return err
+ }
+ derivedPK := delegateInfo.Xpub.PublicKey()
+ pubHash := crypto.Ripemd160(derivedPK)
- if len(parents) > 0 {
- parent = parents[len(parents)-1]
- } else {
- parent, err = c.GetHeaderByHeight(height - 1)
+ addressDet, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
if err != nil {
return err
}
+
+ if addressDet.EncodeAddress() == address.EncodeAddress() {
+ return nil
+ }
}
+ return errors.New("CheckBlock CheckCoinbase error")
+}
+
+func (d *DposType) CheckBlockHeader(header types.BlockHeader) error {
+ blockT := time.Unix(int64(header.Timestamp), 0)
- if parent == nil {
- return errors.New("unknown ancestor")
+ if blockT.Sub(time.Now()).Seconds() > float64(d.BlockIntervalTime) {
+ return errors.New("block time is error")
}
- if _, err = d.snapshot(c, height-1, header.PreviousBlockHash, parents, nil, defaultLoopCntRecalculateSigners); err != nil {
+ if header.Height > d.DposStartHeight {
+ header, _ := d.c.GetHeaderByHeight(d.DposStartHeight)
+ d.setStartTime(header.Timestamp)
+ }
+
+ preHeader, err := d.c.GetHeaderByHash(&header.PreviousBlockHash)
+ if err != nil {
return err
}
- return d.verifySeal(c, header, parents)
+ currentLoopIndex := d.GetLoopIndex(header.Timestamp)
+ currentDelegateIndex := d.GetDelegateIndex(header.Timestamp)
+ prevLoopIndex := d.GetLoopIndex(preHeader.Timestamp)
+ prevDelegateIndex := d.GetDelegateIndex(preHeader.Timestamp)
+ if currentLoopIndex > prevLoopIndex ||
+ (currentLoopIndex == prevLoopIndex && currentDelegateIndex > prevDelegateIndex) {
+ return nil
+ }
+
+ return errors.New("DPoS CheckBlockHeader error")
}
-// verifySeal checks whether the signature contained in the header satisfies the
-// consensus protocol requirements. The method accepts an optional list of parent
-// headers that aren't yet part of the local blockchain to generate the snapshots
-// from.
-func (d *Dpos) verifySeal(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
- height := header.Height
- if height == 0 {
- return errUnknownBlock
+func (d *DposType) CheckBlock(block types.Block, fIsCheckDelegateInfo bool) error {
+ if block.Height > d.DposStartHeight {
+ header, _ := d.c.GetHeaderByHeight(d.DposStartHeight)
+ d.setStartTime(header.Timestamp)
+ }
+
+ blockT := time.Unix(int64(block.Timestamp), 0)
+ if blockT.Sub(time.Now()).Seconds() > float64(d.BlockIntervalTime) {
+ return errors.New("block time is error")
+ }
+ if err := d.CheckCoinbase(block.Transactions[0].TxData, block.Timestamp, block.Height); err != nil {
+ return err
}
- // Retrieve the snapshot needed to verify this header and cache it
- snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, parents, nil, defaultLoopCntRecalculateSigners)
+
+ preBlock, err := d.c.GetBlockByHash(&block.PreviousBlockHash)
if err != nil {
return err
}
- signer := ""
+ currentLoopIndex := d.GetLoopIndex(block.Timestamp)
+ currentDelegateIndex := d.GetDelegateIndex(block.Timestamp)
+ prevLoopIndex := d.GetLoopIndex(preBlock.Timestamp)
+ prevDelegateIndex := d.GetDelegateIndex(preBlock.Timestamp)
- if height > d.config.MaxSignerCount {
- var (
- parent *types.BlockHeader
- err error
- )
- if len(parents) > 0 {
- parent = parents[len(parents)-1]
- } else {
- if parent, err = c.GetHeaderByHeight(height - 1); err != nil {
+ delegateInfo := &DelegateInfo{}
+
+ if currentLoopIndex < prevLoopIndex {
+ return errors.New("Block time exception")
+ } else if currentLoopIndex > prevLoopIndex {
+ if fIsCheckDelegateInfo {
+ if err := d.CheckBlockDelegate(block); err != nil {
return err
}
+ d.ProcessIrreversibleBlock(block.Height, block.Hash())
}
-
- //parent
- xpub := &chainkd.XPub{}
- xpub.UnmarshalText(parent.Coinbase)
- derivedPK := xpub.PublicKey()
- pubHash := crypto.Ripemd160(derivedPK)
- parentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
+ delegateInfo, err = d.GetBlockDelegate(&block)
if err != nil {
return err
}
+ } else {
+ if currentDelegateIndex < prevDelegateIndex {
+ return errors.New("Block time exception")
+ }
- //current
- xpub.UnmarshalText(header.Coinbase)
- derivedPK = xpub.PublicKey()
- pubHash = crypto.Ripemd160(derivedPK)
- currentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
+ delegateInfo, err = d.GetBlockDelegates(&preBlock.BlockHeader)
if err != nil {
return err
}
- signer = currentCoinbase.EncodeAddress()
+ }
- parentHeaderExtra := HeaderExtra{}
- if err = json.Unmarshal(parent.Extra[extraVanity:len(parent.Extra)-extraSeal], &parentHeaderExtra); err != nil {
- return err
- }
+ delegateAddress := d.getBlockForgerAddress(block)
+ if currentDelegateIndex < uint64(len(delegateInfo.Delegates)) &&
+ delegateInfo.Delegates[currentDelegateIndex].DelegateAddress == delegateAddress.EncodeAddress() {
+ return nil
+ }
+ h := block.Hash()
+ return fmt.Errorf("CheckBlock GetDelegateID blockhash:%s error", h.String())
+}
- currentHeaderExtra := HeaderExtra{}
- if err = json.Unmarshal(header.Extra[extraVanity:len(header.Extra)-extraSeal], ¤tHeaderExtra); err != nil {
- return err
+func (d *DposType) CheckBlockDelegate(block types.Block) error {
+ delegateInfo, err := d.GetBlockDelegate(&block)
+ if err != nil {
+ return err
+ }
+ nextDelegateInfoInterface := d.GetNextDelegates(block.Timestamp)
+ nextDelegateInfo := nextDelegateInfoInterface.(*DelegateInfo)
+ if len(delegateInfo.Delegates) != len(nextDelegateInfo.Delegates) {
+ return errors.New("The delegates num is not correct in block")
+ }
+ for index, v := range delegateInfo.Delegates {
+ if v.DelegateAddress != nextDelegateInfo.Delegates[index].DelegateAddress {
+ return errors.New("The delegates address is not correct in block")
}
+ }
- // verify signerqueue
- if height%d.config.MaxSignerCount == 0 {
- err := snap.verifySignerQueue(currentHeaderExtra.SignerQueue)
- if err != nil {
- return err
- }
+ return nil
+}
+func (d *DposType) ProcessIrreversibleBlock(height uint64, hash bc.Hash) {
+ d.lockIrreversibleBlockInfo.Lock()
+ defer d.lockIrreversibleBlockInfo.Unlock()
+ i := 0
+ for i = maxConfirmBlockCount - 1; i >= 0; i-- {
+ if d.irreversibleBlockInfo.heights[i] < 0 || int64(height) < d.irreversibleBlockInfo.heights[i] {
+ d.irreversibleBlockInfo.heights[i] = -1
} else {
- for i := 0; i < int(d.config.MaxSignerCount); i++ {
- if parentHeaderExtra.SignerQueue[i] != currentHeaderExtra.SignerQueue[i] {
- return errInvalidSignerQueue
+ level := (height - uint64(d.irreversibleBlockInfo.heights[i])) * 100
+ if level >= d.MaxDelegateNumber*d.firstIrreversibleThreshold {
+ d.AddIrreversibleBlock(int64(height), hash)
+ } else if level >= d.MaxDelegateNumber*d.secondIrreversibleThreshold {
+ if i == maxConfirmBlockCount-1 {
+ d.AddIrreversibleBlock(int64(height), hash)
+ for k := 0; k < maxConfirmBlockCount-1; k++ {
+ d.irreversibleBlockInfo.heights[k] = d.irreversibleBlockInfo.heights[k+1]
+ d.irreversibleBlockInfo.hashs[k] = d.irreversibleBlockInfo.hashs[k+1]
+ }
+ d.irreversibleBlockInfo.heights[i] = int64(height)
+ d.irreversibleBlockInfo.hashs[i] = hash
+ return
+ } else {
+ d.irreversibleBlockInfo.heights[i+1] = int64(height)
+ d.irreversibleBlockInfo.hashs[i+1] = hash
+ return
}
+
}
- }
- // verify missing signer for punish
- parentSignerMissing := getSignerMissing(parentCoinbase.EncodeAddress(), currentCoinbase.EncodeAddress(), parentHeaderExtra)
- if len(parentSignerMissing) != len(currentHeaderExtra.SignerMissing) {
- return errPunishedMissing
- }
- for i, signerMissing := range currentHeaderExtra.SignerMissing {
- if parentSignerMissing[i] != signerMissing {
- return errPunishedMissing
+ for k := 0; k < maxConfirmBlockCount; k++ {
+ d.irreversibleBlockInfo.heights[k] = -1
}
- }
+ d.irreversibleBlockInfo.heights[0] = int64(height)
+ d.irreversibleBlockInfo.hashs[0] = hash
+ return
+ }
}
-
- if !snap.inturn(signer, header.Timestamp) {
- return errUnauthorized
+ if i < 0 {
+ d.irreversibleBlockInfo.heights[0] = int64(height)
+ d.irreversibleBlockInfo.hashs[0] = hash
}
-
- return nil
}
-// Prepare implements consensus.Engine, preparing all the consensus fields of the header for running the transactions on top.
-func (d *Dpos) Prepare(c chain.Chain, header *types.BlockHeader) error {
- if d.config.GenesisTimestamp < uint64(time.Now().Unix()) {
- return nil
- }
+func (d *DposType) getBlockForgerAddress(block types.Block) common.Address {
+ tx := block.Transactions[0].TxData
- if header.Height == 1 {
- for {
- delay := time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now())
- if delay <= time.Duration(0) {
- log.WithFields(log.Fields{"module": module, "time": time.Now()}).Info("Ready for seal block")
- break
- } else if delay > time.Duration(d.config.Period)*time.Second {
- delay = time.Duration(d.config.Period) * time.Second
- }
- log.WithFields(log.Fields{"module": module, "delay": time.Duration(time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now()))}).Info("Waiting for seal block")
- select {
- case <-time.After(delay):
- continue
+ if len(tx.Inputs) == 1 && tx.Inputs[0].InputType() == types.CoinbaseInputType {
+ address, err := common.NewAddressWitnessPubKeyHash(tx.Outputs[0].ControlProgram[2:], &consensus.ActiveNetParams)
+ if err != nil {
+ address, err := common.NewAddressWitnessScriptHash(tx.Outputs[0].ControlProgram[2:], &consensus.ActiveNetParams)
+ if err != nil {
+ return nil
}
+ return address
}
+ return address
}
+
return nil
}
-func (d *Dpos) Finalize(c chain.Chain, header *types.BlockHeader, txs []*bc.Tx) error {
- height := header.Height
- parent, err := c.GetHeaderByHeight(height - 1)
- if parent == nil {
- return err
- }
- //parent
- var xpub chainkd.XPub
- xpub.UnmarshalText(parent.Coinbase)
- pubHash := crypto.Ripemd160(xpub.PublicKey())
- parentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
- if err != nil {
- return err
- }
+func (d *DposType) IsValidBlockCheckIrreversibleBlock(height uint64, hash bc.Hash) error {
+ d.lockIrreversibleBlockInfo.Lock()
+ defer d.lockIrreversibleBlockInfo.Unlock()
- //current
- xpub.UnmarshalText(header.Coinbase)
- pubHash = crypto.Ripemd160(xpub.PublicKey())
- currentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
- if err != nil {
- return err
+ if h, ok := d.irreversibleBlockInfo.HeightHash[int64(height)]; ok {
+ if h != hash {
+ return fmt.Errorf("invalid block[%d:%s]", height, hash.String())
+ }
}
- //header.Timestamp
- t := new(big.Int).Add(new(big.Int).SetUint64(parent.Timestamp), new(big.Int).SetUint64(d.config.Period))
- header.Timestamp = t.Uint64()
-
- if header.Timestamp < uint64(time.Now().Unix()) {
- header.Timestamp = uint64(time.Now().Unix())
- }
+ return nil
+}
- if len(header.Extra) < extraVanity {
- header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
+func (d *DposType) ReadIrreversibleBlockInfo(info *IrreversibleBlockInfo) error {
+ f, err := os.Open(d.irreversibleBlockFileName)
+ if err != nil {
+ return err
}
-
- header.Extra = header.Extra[:extraVanity]
- // genesisVotes write direct into snapshot, which number is 1
- var genesisVotes []*Vote
- parentHeaderExtra := HeaderExtra{}
- currentHeaderExtra := HeaderExtra{}
- if height == 1 {
- alreadyVote := make(map[string]struct{})
- for _, voter := range d.config.SelfVoteSigners {
- if _, ok := alreadyVote[voter]; !ok {
- genesisVotes = append(genesisVotes, &Vote{
- Voter: voter,
- Candidate: voter,
- Stake: 0,
- //Stake: state.GetBalance(voter),
- })
- alreadyVote[voter] = struct{}{}
+ defer f.Close()
+ buf := bufio.NewReader(f)
+ for {
+ line, err := buf.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ return nil
}
+ return err
}
- } else {
- parentHeaderExtraByte := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
- if err := json.Unmarshal(parentHeaderExtraByte, &parentHeaderExtra); err != nil {
+ line = strings.TrimSpace(line)
+ var height int64
+ var hashString string
+ n, err := fmt.Sscanf(line, "%d;%s\n", &height, &hashString)
+ if err != nil || n != 2 {
+ return errors.New("parse error for ReadIrreversibleBlockInfo ")
+ }
+ var hash bc.Hash
+ if err := hash.UnmarshalText([]byte(hashString)); err != nil {
return err
}
- currentHeaderExtra.ConfirmedBlockNumber = parentHeaderExtra.ConfirmedBlockNumber
- currentHeaderExtra.SignerQueue = parentHeaderExtra.SignerQueue
- currentHeaderExtra.LoopStartTime = parentHeaderExtra.LoopStartTime
- currentHeaderExtra.SignerMissing = getSignerMissing(parentCoinbase.EncodeAddress(), currentCoinbase.EncodeAddress(), parentHeaderExtra)
+ d.AddIrreversibleBlock(height, hash)
}
+}
- // calculate votes write into header.extra
- currentHeaderExtra, err = d.processCustomTx(currentHeaderExtra, c, header, txs)
- if err != nil {
- return err
+type Int64Slice []int64
+
+func (a Int64Slice) Len() int {
+ return len(a)
+}
+func (a Int64Slice) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+func (a Int64Slice) Less(i, j int) bool {
+ return a[i] < a[j]
+}
+
+func (d *DposType) WriteIrreversibleBlockInfo() error {
+ if len(d.irreversibleBlockInfo.HeightHash) == 0 {
+ return nil
}
- // Assemble the voting snapshot to check which votes make sense
- snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, nil, genesisVotes, defaultLoopCntRecalculateSigners)
+
+ f, err := os.Create(d.irreversibleBlockFileName)
if err != nil {
return err
}
-
- currentHeaderExtra.ConfirmedBlockNumber = snap.getLastConfirmedBlockNumber(currentHeaderExtra.CurrentBlockConfirmations).Uint64()
- // write signerQueue in first header, from self vote signers in genesis block
- if height == 1 {
- currentHeaderExtra.LoopStartTime = d.config.GenesisTimestamp
- for i := 0; i < int(d.config.MaxSignerCount); i++ {
- currentHeaderExtra.SignerQueue = append(currentHeaderExtra.SignerQueue, d.config.SelfVoteSigners[i%len(d.config.SelfVoteSigners)])
- }
+ defer f.Close()
+ w := bufio.NewWriter(f)
+ var keys []int64
+ for k := range d.irreversibleBlockInfo.HeightHash {
+ keys = append(keys, k)
}
- if height%d.config.MaxSignerCount == 0 {
- currentHeaderExtra.LoopStartTime = currentHeaderExtra.LoopStartTime + d.config.Period*d.config.MaxSignerCount
- // create random signersQueue in currentHeaderExtra by snapshot.Tally
- currentHeaderExtra.SignerQueue = []string{}
- newSignerQueue, err := snap.createSignerQueue()
- if err != nil {
- return err
- }
- currentHeaderExtra.SignerQueue = newSignerQueue
+ sort.Sort(Int64Slice(keys))
+ for _, k := range keys {
+ data, _ := d.irreversibleBlockInfo.HeightHash[k].MarshalText()
+ line := fmt.Sprintf("%d;%s\n", k, string(data))
+ w.WriteString(line)
}
- // encode header.extra
- currentHeaderExtraEnc, err := json.Marshal(currentHeaderExtra)
- if err != nil {
+
+ if err := w.Flush(); err != nil {
return err
}
- header.Extra = append(header.Extra, currentHeaderExtraEnc...)
- header.Extra = append(header.Extra, make([]byte, extraSeal)...)
+
return nil
}
-func (d *Dpos) Seal(c chain.Chain, block *types.Block) (*types.Block, error) {
- header := block.BlockHeader
- height := header.Height
- if height == 0 {
- return nil, errUnknownBlock
+func (d *DposType) AddIrreversibleBlock(height int64, hash bc.Hash) {
+ for k, _ := range d.irreversibleBlockInfo.HeightHash {
+ if len(d.irreversibleBlockInfo.HeightHash) > d.maxIrreversibleCount {
+ delete(d.irreversibleBlockInfo.HeightHash, k)
+ } else {
+ break
+ }
}
+ d.irreversibleBlockInfo.HeightHash[height] = hash
+ d.vote.DeleteInvalidVote(uint64(height))
+}
- if d.config.Period == 0 && len(block.Transactions) == 0 {
- return nil, errWaitTransactions
- }
- // Bail out if we're unauthorized to sign a block
- snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, nil, nil, defaultLoopCntRecalculateSigners)
- if err != nil {
- return nil, err
- }
- if !snap.inturn(d.signer, header.Timestamp) {
- return nil, errUnauthorized
- }
+func (d *DposType) GetSuperForgerAddress() common.Address {
+ return d.superForgerAddress
+}
- var xPrv chainkd.XPrv
- if config.CommonConfig.Consensus.Dpos.XPrv == "" {
- return nil, errors.New("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
- sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
- pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
+func (d *DposType) GetIrreversibleBlock() {
- control, err := vmutil.P2WPKHProgram([]byte(pubHash))
- if err != nil {
- return nil, err
- }
+}
- block.Proof = types.Proof{Sign: sign, ControlProgram: control}
- return block, nil
+func (d *DposType) GetOldBlockHeight() uint64 {
+ return d.vote.GetOldBlockHeight()
}
-func (d *Dpos) IsSealer(c chain.Chain, hash bc.Hash, header *types.BlockHeader, headerTime uint64) (bool, error) {
- var (
- snap *Snapshot
- headers []*types.BlockHeader
- )
- h := hash
- height := header.Height
- for snap == nil {
- // If an in-memory snapshot was found, use that
- if s, ok := d.recents.Get(h); ok {
- snap = s.(*Snapshot)
- break
- }
- // If an on-disk checkpoint snapshot can be found, use that
- if height%checkpointInterval == 0 {
- if s, err := loadSnapshot(d.config, d.signatures, d.store, h); err == nil {
- log.WithFields(log.Fields{"func": "IsSealer", "number": height, "hash": h}).Warn("Loaded voting snapshot from disk")
- snap = s
- break
- } else {
- log.Warn("loadSnapshot:", err)
- }
- }
+func (d *DposType) GetOldBlockHash() bc.Hash {
+ return d.vote.GetOldBlockHash()
+}
- if height == 0 {
- genesis, err := c.GetHeaderByHeight(0)
- if err != nil {
- return false, err
- }
- var genesisVotes []*Vote
- alreadyVote := make(map[string]struct{})
- for _, voter := range d.config.SelfVoteSigners {
- if _, ok := alreadyVote[voter]; !ok {
- genesisVotes = append(genesisVotes, &Vote{
- Voter: voter,
- Candidate: voter,
- Stake: 0,
- //Stake: state.GetBalance(voter),
- })
- alreadyVote[voter] = struct{}{}
- }
- }
- snap = newSnapshot(d.config, d.signatures, genesis.Hash(), genesisVotes, defaultLoopCntRecalculateSigners)
- if err := snap.store(d.store); err != nil {
- return false, err
- }
- log.Info("Stored genesis voting snapshot to disk")
- break
- }
+func (d *DposType) ListDelegates() map[string]string {
+ return d.vote.ListDelegates()
+}
- header, err := c.GetHeaderByHeight(height)
- if header == nil || err != nil {
- return false, errors.New("unknown ancestor")
- }
+func (d *DposType) GetDelegateVotes(delegate string) uint64 {
+ return d.vote.GetDelegateVotes(delegate)
+}
- height, h = height-1, header.PreviousBlockHash
- }
+func (d *DposType) GetDelegateVoters(delegate string) []string {
+ return d.vote.GetDelegateVoters(delegate)
+}
- snap, err := snap.apply(headers)
- if err != nil {
- return false, err
- }
+func (d *DposType) GetDelegate(name string) string {
+ return d.vote.GetDelegate(name)
- d.recents.Add(snap.Hash, snap)
+}
- if snap != nil {
- loopIndex := int((headerTime-snap.LoopStartTime)/snap.config.Period) % len(snap.Signers)
- if loopIndex >= len(snap.Signers) {
- return false, nil
- } else if *snap.Signers[loopIndex] != d.signer {
- return false, nil
+func (d *DposType) GetDelegateName(address string) string {
+ return d.vote.GetDelegateName(address)
+}
- }
- return true, nil
- } else {
- return false, nil
- }
+func (d *DposType) GetAddressBalance(address string) uint64 {
+ return d.vote.GetAddressBalance(address)
}
-// snapshot retrieves the authorization snapshot at a given point in time.
-func (d *Dpos) snapshot(c chain.Chain, number uint64, hash bc.Hash, parents []*types.BlockHeader, genesisVotes []*Vote, lcrs uint64) (*Snapshot, error) {
+func (d *DposType) GetVotedDelegates(voter string) []string {
+ return d.vote.GetVotedDelegates(voter)
+}
- var (
- headers []*types.BlockHeader
- snap *Snapshot
- )
- h := hash
+func (d *DposType) HaveVote(voter, delegate string) bool {
+ return d.vote.HaveVote(voter, delegate)
+}
- for snap == nil {
- // If an in-memory snapshot was found, use that
- if s, ok := d.recents.Get(h); ok {
- snap = s.(*Snapshot)
- break
- }
- // If an on-disk checkpoint snapshot can be found, use that
- if number%checkpointInterval == 0 {
- if s, err := loadSnapshot(d.config, d.signatures, d.store, h); err == nil {
- log.WithFields(log.Fields{"number": number, "hash": h}).Warn("Loaded voting snapshot from disk")
- snap = s
- break
- }
- }
- if number == 0 {
- genesis, err := c.GetHeaderByHeight(0)
- if err != nil {
- return nil, err
- }
- if err := d.VerifySeal(c, genesis); err != nil {
- return nil, err
- }
+func (d *DposType) HaveDelegate(name, delegate string) bool {
+ return d.vote.HaveDelegate(name, delegate)
+}
- snap = newSnapshot(d.config, d.signatures, genesis.Hash(), genesisVotes, lcrs)
- if err := snap.store(d.store); err != nil {
- return nil, err
- }
- log.Info("Stored genesis voting snapshot to disk")
- break
- }
- var header *types.BlockHeader
- if len(parents) > 0 {
- header = parents[len(parents)-1]
- if header.Hash() != h || header.Height != number {
- return nil, errors.New("unknown ancestor")
- }
- parents = parents[:len(parents)-1]
- } else {
- var err error
- header, err = c.GetHeaderByHeight(number)
- if header == nil || err != nil {
- return nil, errors.New("unknown ancestor")
- }
- }
- headers = append(headers, header)
- number, h = number-1, header.PreviousBlockHash
+func (d *DposType) Finish() error {
+ header := d.c.BestBlockHeader()
+ if err := d.vote.Store(header.Height, header.Hash()); err != nil {
+ return err
}
- // Previous snapshot found, apply any pending headers on top of it
- for i := 0; i < len(headers)/2; i++ {
- headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
- }
- snap, err := snap.apply(headers)
- if err != nil {
- return nil, err
+ if err := d.WriteIrreversibleBlockInfo(); err != nil {
+ return err
}
- d.recents.Add(snap.Hash, snap)
- // If we've generated a new checkpoint snapshot, save to disk
- if snap.Number%checkpointInterval == 0 && len(headers) > 0 {
- if err = snap.store(d.store); err != nil {
- return nil, err
- }
- log.Info("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash)
- }
- return snap, err
+ return nil
}
-// Get the signer missing from last signer till header.Coinbase
-func getSignerMissing(lastSigner string, currentSigner string, extra HeaderExtra) []string {
+func SortDelegate(delegates []Delegate, t uint64) []Delegate {
+ var result []Delegate
+ r := getRand(uint64(len(delegates)), int64(t))
+ for _, i := range r {
+ result = append(result, delegates[i])
+ }
+ return result
+}
- var signerMissing []string
- recordMissing := false
- for _, signer := range extra.SignerQueue {
- if signer == lastSigner {
- recordMissing = true
+func getRand(num uint64, seed int64) []uint64 {
+ rand.Seed(seed)
+ var r []uint64
+ s := make(map[uint64]bool)
+ for {
+ v := rand.Uint64()
+ v %= num
+ if _, ok := s[v]; ok {
continue
}
- if signer == currentSigner {
+ s[v] = true
+ r = append(r, v)
+ if uint64(len(r)) >= num {
break
}
- if recordMissing {
- signerMissing = append(signerMissing, signer)
- }
}
- return signerMissing
+
+ return r
}
+++ /dev/null
-package dpos
-
-import (
- "bytes"
- "sort"
-
- "github.com/vapor/protocol/bc"
-)
-
-type TallyItem struct {
- addr string
- stake uint64
-}
-
-type TallySlice []TallyItem
-
-func (s TallySlice) Len() int { return len(s) }
-func (s TallySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s TallySlice) Less(i, j int) bool {
- //we need sort reverse, so ...
- if s[i].stake > s[j].stake {
- return true
-
- } else if s[i].stake < s[j].stake {
- return false
- }
- // if the stake equal
- //return bytes.Compare(s[i].addr.ScriptAddress(), s[j].addr.ScriptAddress()) > 0
- return s[i].addr > s[j].addr
-}
-
-type SignerItem struct {
- addr string
- hash bc.Hash
-}
-
-type SignerSlice []SignerItem
-
-func (s SignerSlice) Len() int { return len(s) }
-func (s SignerSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s SignerSlice) Less(i, j int) bool {
- return bytes.Compare(s[i].hash.Bytes(), s[j].hash.Bytes()) > 0
-}
-
-// verify the SignerQueue base on block hash
-func (s *Snapshot) verifySignerQueue(signerQueue []string) error {
-
- if len(signerQueue) > int(s.config.MaxSignerCount) {
- return errInvalidSignerQueue
- }
- sq, err := s.createSignerQueue()
- if err != nil {
- return err
- }
- if len(sq) == 0 || len(sq) != len(signerQueue) {
- return errInvalidSignerQueue
- }
- for i, signer := range signerQueue {
- if signer != sq[i] {
- return errInvalidSignerQueue
- }
- }
-
- return nil
-}
-
-func (s *Snapshot) buildTallySlice() TallySlice {
- var tallySlice TallySlice
- for address, stake := range s.Tally {
- if !candidateNeedPD || s.isCandidate(address) {
- if _, ok := s.Punished[address]; ok {
- var creditWeight uint64
- if s.Punished[address] > defaultFullCredit-minCalSignerQueueCredit {
- creditWeight = minCalSignerQueueCredit
- } else {
- creditWeight = defaultFullCredit - s.Punished[address]
- }
- tallySlice = append(tallySlice, TallyItem{address, stake * creditWeight})
- } else {
- tallySlice = append(tallySlice, TallyItem{address, stake * defaultFullCredit})
- }
- }
- }
- return tallySlice
-}
-
-func (s *Snapshot) createSignerQueue() ([]string, error) {
- if (s.Number+1)%s.config.MaxSignerCount != 0 || s.Hash != s.HistoryHash[len(s.HistoryHash)-1] {
- return nil, errCreateSignerQueueNotAllowed
- }
-
- var signerSlice SignerSlice
- var topStakeAddress []string
- if (s.Number+1)%(s.config.MaxSignerCount*s.LCRS) == 0 {
- // before recalculate the signers, clear the candidate is not in snap.Candidates
-
- // only recalculate signers from to tally per 10 loop,
- // other loop end just reset the order of signers by block hash (nearly random)
- tallySlice := s.buildTallySlice()
- sort.Sort(TallySlice(tallySlice))
- queueLength := int(s.config.MaxSignerCount)
- if queueLength > len(tallySlice) {
- queueLength = len(tallySlice)
- }
- if queueLength == defaultOfficialMaxSignerCount && len(tallySlice) > defaultOfficialThirdLevelCount {
- for i, tallyItem := range tallySlice[:defaultOfficialFirstLevelCount] {
- signerSlice = append(signerSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
- var signerSecondLevelSlice, signerThirdLevelSlice, signerLastLevelSlice SignerSlice
- // 60%
- for i, tallyItem := range tallySlice[defaultOfficialFirstLevelCount:defaultOfficialSecondLevelCount] {
- signerSecondLevelSlice = append(signerSecondLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
- sort.Sort(SignerSlice(signerSecondLevelSlice))
- signerSlice = append(signerSlice, signerSecondLevelSlice[:6]...)
- // 40%
- for i, tallyItem := range tallySlice[defaultOfficialSecondLevelCount:defaultOfficialThirdLevelCount] {
- signerThirdLevelSlice = append(signerThirdLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
- sort.Sort(SignerSlice(signerThirdLevelSlice))
- signerSlice = append(signerSlice, signerThirdLevelSlice[:4]...)
- // choose 1 from last
- for i, tallyItem := range tallySlice[defaultOfficialThirdLevelCount:] {
- signerLastLevelSlice = append(signerLastLevelSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
- sort.Sort(SignerSlice(signerLastLevelSlice))
- signerSlice = append(signerSlice, signerLastLevelSlice[0])
-
- } else {
- for i, tallyItem := range tallySlice[:queueLength] {
- signerSlice = append(signerSlice, SignerItem{tallyItem.addr, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
-
- }
-
- } else {
- for i, signer := range s.Signers {
- signerSlice = append(signerSlice, SignerItem{*signer, s.HistoryHash[len(s.HistoryHash)-1-i]})
- }
- }
-
- sort.Sort(SignerSlice(signerSlice))
- // Set the top candidates in random order base on block hash
- if len(signerSlice) == 0 {
- return nil, errSignerQueueEmpty
- }
- for i := 0; i < int(s.config.MaxSignerCount); i++ {
- topStakeAddress = append(topStakeAddress, signerSlice[i%len(signerSlice)].addr)
- }
-
- return topStakeAddress, nil
-
-}
+++ /dev/null
-package dpos
-
-import (
- "encoding/json"
- "errors"
- "math/big"
- "sort"
- "time"
-
- lru "github.com/hashicorp/golang-lru"
- "github.com/vapor/config"
- "github.com/vapor/protocol"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
-)
-
-const (
- defaultFullCredit = 1000 // no punished
- missingPublishCredit = 100 // punished for missing one block seal
- signRewardCredit = 10 // seal one block
- autoRewardCredit = 1 // credit auto recover for each block
- minCalSignerQueueCredit = 300 // when calculate the signerQueue
- defaultOfficialMaxSignerCount = 21 // official max signer count
- defaultOfficialFirstLevelCount = 10 // official first level , 100% in signer queue
- defaultOfficialSecondLevelCount = 20 // official second level, 60% in signer queue
- defaultOfficialThirdLevelCount = 30 // official third level, 40% in signer queue
- // the credit of one signer is at least minCalSignerQueueCredit
- candidateStateNormal = 1
- candidateMaxLen = 500 // if candidateNeedPD is false and candidate is more than candidateMaxLen, then minimum tickets candidates will be remove in each LCRS*loop
-)
-
-var errIncorrectTallyCount = errors.New("incorrect tally count")
-
-type Snapshot struct {
- config *config.DposConfig // Consensus engine configuration parameters
- sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
- LCRS uint64 // Loop count to recreate signers from top tally
- Period uint64 `json:"period"` // Period of seal each block
- Number uint64 `json:"number"` // Block Number where the snapshot was created
- ConfirmedNumber uint64 `json:"confirmed_number"` // Block Number confirmed when the snapshot was created
- Hash bc.Hash `json:"hash"` // Block hash where the snapshot was created
- HistoryHash []bc.Hash `json:"historyHash"` // Block hash list for two recent loop
- Signers []*string `json:"signers"` // Signers queue in current header
- Votes map[string]*Vote `json:"votes"` // All validate votes from genesis block
- Tally map[string]uint64 `json:"tally"` // Stake for each candidate address
- Voters map[string]uint64 `json:"voters"` // Block height for each voter address
- Candidates map[string]uint64 `json:"candidates"` // Candidates for Signers (0- adding procedure 1- normal 2- removing procedure)
- Punished map[string]uint64 `json:"punished"` // The signer be punished count cause of missing seal
- Confirmations map[uint64][]string `json:"confirms"` // The signer confirm given block height
- Proposals map[bc.Hash]*Proposal `json:"proposals"` // The Proposals going or success (failed proposal will be removed)
- HeaderTime uint64 `json:"headerTime"` // Time of the current header
- LoopStartTime uint64 `json:"loopStartTime"` // Start Time of the current loop
-}
-
-// newSnapshot creates a new snapshot with the specified startup parameters. only ever use if for
-// the genesis block.
-func newSnapshot(config *config.DposConfig, sigcache *lru.ARCCache, hash bc.Hash, votes []*Vote, lcrs uint64) *Snapshot {
-
- snap := &Snapshot{
- config: config,
- sigcache: sigcache,
- LCRS: lcrs,
- Period: config.Period,
- Number: 0,
- ConfirmedNumber: 0,
- Hash: hash,
- HistoryHash: []bc.Hash{},
- Signers: []*string{},
- Votes: make(map[string]*Vote),
- Tally: make(map[string]uint64),
- Voters: make(map[string]uint64),
- Punished: make(map[string]uint64),
- Candidates: make(map[string]uint64),
- Confirmations: make(map[uint64][]string),
- Proposals: make(map[bc.Hash]*Proposal),
- HeaderTime: uint64(time.Now().Unix()) - 1,
- LoopStartTime: config.GenesisTimestamp,
- }
- snap.HistoryHash = append(snap.HistoryHash, hash)
- for _, vote := range votes {
- // init Votes from each vote
- snap.Votes[vote.Voter] = vote
- // init Tally
- _, ok := snap.Tally[vote.Candidate]
- if !ok {
- snap.Tally[vote.Candidate] = 0
- }
- snap.Tally[vote.Candidate] += vote.Stake
- // init Voters
- snap.Voters[vote.Voter] = 0 // block height is 0 , vote in genesis block
- // init Candidates
- snap.Candidates[vote.Voter] = candidateStateNormal
- }
-
- for i := 0; i < int(config.MaxSignerCount); i++ {
- snap.Signers = append(snap.Signers, &config.SelfVoteSigners[i%len(config.SelfVoteSigners)])
- }
-
- return snap
-}
-
-// loadSnapshot loads an existing snapshot from the database.
-func loadSnapshot(config *config.DposConfig, sigcache *lru.ARCCache, store protocol.Store, hash bc.Hash) (*Snapshot, error) {
- data, err := store.Get(&hash)
- if err != nil {
- return nil, err
- }
- snap := new(Snapshot)
- if err := json.Unmarshal(data, snap); err != nil {
- return nil, err
- }
- snap.config = config
- snap.sigcache = sigcache
- return snap, nil
-}
-
-// store inserts the snapshot into the database.
-func (s *Snapshot) store(store protocol.Store) error {
- data, err := json.Marshal(s)
- if err != nil {
- return err
- }
- return store.Set(&s.Hash, data)
-}
-
-// copy creates a deep copy of the snapshot, though not the individual votes.
-func (s *Snapshot) copy() *Snapshot {
- cpy := &Snapshot{
- config: s.config,
- sigcache: s.sigcache,
- LCRS: s.LCRS,
- Period: s.Period,
- Number: s.Number,
- ConfirmedNumber: s.ConfirmedNumber,
- Hash: s.Hash,
- HistoryHash: make([]bc.Hash, len(s.HistoryHash)),
-
- Signers: make([]*string, len(s.Signers)),
- Votes: make(map[string]*Vote),
- Tally: make(map[string]uint64),
- Voters: make(map[string]uint64),
- Candidates: make(map[string]uint64),
- Punished: make(map[string]uint64),
- Proposals: make(map[bc.Hash]*Proposal),
- Confirmations: make(map[uint64][]string),
-
- HeaderTime: s.HeaderTime,
- LoopStartTime: s.LoopStartTime,
- }
- copy(cpy.HistoryHash, s.HistoryHash)
- copy(cpy.Signers, s.Signers)
- for voter, vote := range s.Votes {
- cpy.Votes[voter] = &Vote{
- Voter: vote.Voter,
- Candidate: vote.Candidate,
- Stake: vote.Stake,
- }
- }
- for candidate, tally := range s.Tally {
- cpy.Tally[candidate] = tally
- }
- for voter, number := range s.Voters {
- cpy.Voters[voter] = number
- }
- for candidate, state := range s.Candidates {
- cpy.Candidates[candidate] = state
- }
- for signer, cnt := range s.Punished {
- cpy.Punished[signer] = cnt
- }
- for blockNumber, confirmers := range s.Confirmations {
- cpy.Confirmations[blockNumber] = make([]string, len(confirmers))
- copy(cpy.Confirmations[blockNumber], confirmers)
- }
- for txHash, proposal := range s.Proposals {
- cpy.Proposals[txHash] = proposal.copy()
- }
-
- return cpy
-}
-
-// apply creates a new authorization snapshot by applying the given headers to
-// the original one.
-func (s *Snapshot) apply(headers []*types.BlockHeader) (*Snapshot, error) {
- // Allow passing in no headers for cleaner code
- if len(headers) == 0 {
- return s, nil
- }
- // Sanity check that the headers can be applied
- for i := 0; i < len(headers)-1; i++ {
- if headers[i+1].Height != headers[i].Height+1 {
- return nil, errInvalidVotingChain
- }
- }
- if headers[0].Height != s.Number+1 {
- return nil, errInvalidVotingChain
- }
- // Iterate through the headers and create a new snapshot
- snap := s.copy()
- for _, header := range headers {
-
- // Resolve the authorization key and check against signers
- coinbase, err := ecrecover(header, s.sigcache, nil)
- if err != nil {
- return nil, err
- }
-
- headerExtra := HeaderExtra{}
- if err := json.Unmarshal(header.Extra[extraVanity:len(header.Extra)-extraSeal], &headerExtra); err != nil {
- return nil, err
- }
-
- snap.HeaderTime = header.Timestamp
- snap.LoopStartTime = headerExtra.LoopStartTime
- snap.Signers = nil
- for i := range headerExtra.SignerQueue {
- snap.Signers = append(snap.Signers, &headerExtra.SignerQueue[i])
- }
-
- snap.ConfirmedNumber = headerExtra.ConfirmedBlockNumber
-
- if len(snap.HistoryHash) >= int(s.config.MaxSignerCount)*2 {
- snap.HistoryHash = snap.HistoryHash[1 : int(s.config.MaxSignerCount)*2]
- }
-
- snap.HistoryHash = append(snap.HistoryHash, header.Hash())
-
- // deal the new confirmation in this block
- snap.updateSnapshotByConfirmations(headerExtra.CurrentBlockConfirmations)
-
- // deal the new vote from voter
- snap.updateSnapshotByVotes(headerExtra.CurrentBlockVotes, header.Height)
-
- // deal the snap related with punished
- snap.updateSnapshotForPunish(headerExtra.SignerMissing, header.Height, coinbase)
-
- // deal proposals
- snap.updateSnapshotByProposals(headerExtra.CurrentBlockProposals, header.Height)
-
- // deal declares
- snap.updateSnapshotByDeclares(headerExtra.CurrentBlockDeclares, header.Height)
-
- // calculate proposal result
- snap.calculateProposalResult(header.Height)
-
- // check the len of candidate if not candidateNeedPD
- if !candidateNeedPD && (snap.Number+1)%(snap.config.MaxSignerCount*snap.LCRS) == 0 && len(snap.Candidates) > candidateMaxLen {
- snap.removeExtraCandidate()
- }
-
- }
- snap.Number += uint64(len(headers))
- snap.Hash = headers[len(headers)-1].Hash()
- snap.updateSnapshotForExpired()
- err := snap.verifyTallyCnt()
- if err != nil {
- return nil, err
- }
- return snap, nil
-}
-
-func (s *Snapshot) removeExtraCandidate() {
- // remove minimum tickets tally beyond candidateMaxLen
- tallySlice := s.buildTallySlice()
- sort.Sort(TallySlice(tallySlice))
- if len(tallySlice) > candidateMaxLen {
- removeNeedTally := tallySlice[candidateMaxLen:]
- for _, tallySlice := range removeNeedTally {
- delete(s.Candidates, tallySlice.addr)
- }
- }
-}
-
-func (s *Snapshot) verifyTallyCnt() error {
-
- tallyTarget := make(map[string]uint64)
- for _, v := range s.Votes {
- if _, ok := tallyTarget[v.Candidate]; ok {
- tallyTarget[v.Candidate] = tallyTarget[v.Candidate] + v.Stake
- } else {
- tallyTarget[v.Candidate] = v.Stake
- }
- }
- for address, tally := range s.Tally {
- if targetTally, ok := tallyTarget[address]; ok && targetTally == tally {
- continue
- } else {
- return errIncorrectTallyCount
- }
- }
-
- return nil
-}
-
-func (s *Snapshot) updateSnapshotByDeclares(declares []Declare, headerHeight uint64) {
- for _, declare := range declares {
- if proposal, ok := s.Proposals[declare.ProposalHash]; ok {
- // check the proposal enable status and valid block number
- if proposal.ReceivedNumber+proposal.ValidationLoopCnt*s.config.MaxSignerCount < headerHeight || !s.isCandidate(declare.Declarer) {
- continue
- }
- // check if this signer already declare on this proposal
- alreadyDeclare := false
- for _, v := range proposal.Declares {
- if v.Declarer == declare.Declarer {
- // this declarer already declare for this proposal
- alreadyDeclare = true
- break
- }
- }
- if alreadyDeclare {
- continue
- }
- // add declare to proposal
- s.Proposals[declare.ProposalHash].Declares = append(s.Proposals[declare.ProposalHash].Declares,
- &Declare{declare.ProposalHash, declare.Declarer, declare.Decision})
-
- }
- }
-}
-
-func (s *Snapshot) calculateProposalResult(headerHeight uint64) {
-
- for hashKey, proposal := range s.Proposals {
- // the result will be calculate at receiverdNumber + vlcnt + 1
- if proposal.ReceivedNumber+proposal.ValidationLoopCnt*s.config.MaxSignerCount+1 == headerHeight {
- // calculate the current stake of this proposal
- judegmentStake := big.NewInt(0)
- for _, tally := range s.Tally {
- judegmentStake.Add(judegmentStake, new(big.Int).SetUint64(tally))
- }
- judegmentStake.Mul(judegmentStake, big.NewInt(2))
- judegmentStake.Div(judegmentStake, big.NewInt(3))
- // calculate declare stake
- yesDeclareStake := big.NewInt(0)
- for _, declare := range proposal.Declares {
- if declare.Decision {
- if _, ok := s.Tally[declare.Declarer]; ok {
- yesDeclareStake.Add(yesDeclareStake, new(big.Int).SetUint64(s.Tally[declare.Declarer]))
- }
- }
- }
- if yesDeclareStake.Cmp(judegmentStake) > 0 {
- // process add candidate
- switch proposal.ProposalType {
- case proposalTypeCandidateAdd:
- if candidateNeedPD {
- s.Candidates[s.Proposals[hashKey].Candidate] = candidateStateNormal
- }
- case proposalTypeCandidateRemove:
- if _, ok := s.Candidates[proposal.Candidate]; ok && candidateNeedPD {
- delete(s.Candidates, proposal.Candidate)
- }
- case proposalTypeMinerRewardDistributionModify:
- minerRewardPerThousand = s.Proposals[hashKey].MinerRewardPerThousand
- }
- }
- }
- }
-}
-
-func (s *Snapshot) updateSnapshotByProposals(proposals []Proposal, headerHeight uint64) {
- for _, proposal := range proposals {
- proposal.ReceivedNumber = headerHeight
- s.Proposals[proposal.Hash] = &proposal
- }
-}
-
-func (s *Snapshot) updateSnapshotForExpired() {
- // deal the expired vote
- var expiredVotes []*Vote
- for voterAddress, voteNumber := range s.Voters {
- if s.Number-voteNumber > s.config.Epoch {
- // clear the vote
- if expiredVote, ok := s.Votes[voterAddress]; ok {
- expiredVotes = append(expiredVotes, expiredVote)
- }
- }
- }
- // remove expiredVotes only enough voters left
- if uint64(len(s.Voters)-len(expiredVotes)) >= s.config.MaxSignerCount {
- for _, expiredVote := range expiredVotes {
- s.Tally[expiredVote.Candidate] -= expiredVote.Stake
- // TODO
- if s.Tally[expiredVote.Candidate] == 0 {
- delete(s.Tally, expiredVote.Candidate)
- }
- delete(s.Votes, expiredVote.Voter)
- delete(s.Voters, expiredVote.Voter)
- }
- }
-
- // deal the expired confirmation
- for blockNumber := range s.Confirmations {
- if s.Number-blockNumber > s.config.MaxSignerCount {
- delete(s.Confirmations, blockNumber)
- }
- }
-
- // TODO
- // remove 0 stake tally
-
- for address, tally := range s.Tally {
- if tally <= 0 && uint64(len(s.Tally)) > s.config.MaxSignerCount {
- delete(s.Tally, address)
- }
- }
-}
-
-func (s *Snapshot) updateSnapshotByConfirmations(confirmations []Confirmation) {
- for _, confirmation := range confirmations {
- _, ok := s.Confirmations[confirmation.BlockNumber]
- if !ok {
- s.Confirmations[confirmation.BlockNumber] = []string{}
- }
- addConfirmation := true
- for _, address := range s.Confirmations[confirmation.BlockNumber] {
- if confirmation.Signer == address {
- addConfirmation = false
- break
- }
- }
- if addConfirmation == true {
- s.Confirmations[confirmation.BlockNumber] = append(s.Confirmations[confirmation.BlockNumber], confirmation.Signer)
- }
- }
-}
-
-func (s *Snapshot) updateSnapshotByVotes(votes []Vote, headerHeight uint64) {
- for _, vote := range votes {
- // update Votes, Tally, Voters data
- if lastVote, ok := s.Votes[vote.Voter]; ok {
- s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] - lastVote.Stake
- }
- if _, ok := s.Tally[vote.Candidate]; ok {
- s.Tally[vote.Candidate] = s.Tally[vote.Candidate] + vote.Stake
- } else {
- s.Tally[vote.Candidate] = vote.Stake
- if !candidateNeedPD {
- s.Candidates[vote.Candidate] = candidateStateNormal
- }
- }
- s.Votes[vote.Voter] = &Vote{vote.Voter, vote.Candidate, vote.Stake}
- s.Voters[vote.Voter] = headerHeight
- }
-}
-
-func (s *Snapshot) updateSnapshotByMPVotes(votes []Vote) {
- for _, txVote := range votes {
- if lastVote, ok := s.Votes[txVote.Voter]; ok {
- s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] - lastVote.Stake
- s.Tally[lastVote.Candidate] = s.Tally[lastVote.Candidate] + txVote.Stake
- s.Votes[txVote.Voter] = &Vote{Voter: txVote.Voter, Candidate: lastVote.Candidate, Stake: txVote.Stake}
- }
- }
-}
-
-func (s *Snapshot) updateSnapshotForPunish(signerMissing []string, headerNumber uint64, coinbase string) {
- // punish the missing signer
- for _, signerMissing := range signerMissing {
- if _, ok := s.Punished[signerMissing]; ok {
- s.Punished[signerMissing] += missingPublishCredit
- } else {
- s.Punished[signerMissing] = missingPublishCredit
- }
- }
- // reduce the punish of sign signer
- if _, ok := s.Punished[coinbase]; ok {
-
- if s.Punished[coinbase] > signRewardCredit {
- s.Punished[coinbase] -= signRewardCredit
- } else {
- delete(s.Punished, coinbase)
- }
- }
- // reduce the punish for all punished
- for signerEach := range s.Punished {
- if s.Punished[signerEach] > autoRewardCredit {
- s.Punished[signerEach] -= autoRewardCredit
- } else {
- delete(s.Punished, signerEach)
- }
- }
-}
-
-// inturn returns if a signer at a given block height is in-turn or not.
-func (s *Snapshot) inturn(signer string, headerTime uint64) bool {
- // if all node stop more than period of one loop
- loopIndex := int((headerTime-s.LoopStartTime)/s.config.Period) % len(s.Signers)
- if loopIndex >= len(s.Signers) {
- return false
- } else if *s.Signers[loopIndex] != signer {
- return false
-
- }
- return true
-}
-
-// check if address belong to voter
-func (s *Snapshot) isVoter(address string) bool {
- if _, ok := s.Voters[address]; ok {
- return true
- }
- return false
-}
-
-// check if address belong to candidate
-func (s *Snapshot) isCandidate(address string) bool {
- if _, ok := s.Candidates[address]; ok {
- return true
- }
- return false
-}
-
-// get last block number meet the confirm condition
-func (s *Snapshot) getLastConfirmedBlockNumber(confirmations []Confirmation) *big.Int {
- cpyConfirmations := make(map[uint64][]string)
- for blockNumber, confirmers := range s.Confirmations {
- cpyConfirmations[blockNumber] = make([]string, len(confirmers))
- copy(cpyConfirmations[blockNumber], confirmers)
- }
- // update confirmation into snapshot
- for _, confirmation := range confirmations {
- _, ok := cpyConfirmations[confirmation.BlockNumber]
- if !ok {
- cpyConfirmations[confirmation.BlockNumber] = []string{}
- }
- addConfirmation := true
- for _, address := range cpyConfirmations[confirmation.BlockNumber] {
- if confirmation.Signer == address {
- addConfirmation = false
- break
- }
- }
- if addConfirmation == true {
- cpyConfirmations[confirmation.BlockNumber] = append(cpyConfirmations[confirmation.BlockNumber], confirmation.Signer)
- }
- }
-
- i := s.Number
- for ; i > s.Number-s.config.MaxSignerCount*2/3+1; i-- {
- if confirmers, ok := cpyConfirmations[i]; ok {
- if len(confirmers) > int(s.config.MaxSignerCount*2/3) {
- return big.NewInt(int64(i))
- }
- }
- }
- return big.NewInt(int64(i))
-}
-package consensus
+package dpos
import (
"encoding/json"
+ "fmt"
+ "io/ioutil"
"os"
"path/filepath"
+ "sort"
+ "strings"
"sync"
- "github.com/vapor/config"
+ cmn "github.com/tendermint/tmlibs/common"
+ "github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
"github.com/vapor/protocol/bc"
)
ForgerFile = "forger.data"
)
-type AddressBalance struct {
- Address string
- Balance int64
-}
-
type Vote struct {
DelegateVoters map[string]map[string]bool
VoterDelegates map[string]map[string]bool
oldBlockHash bc.Hash
}
-var DposVote = Vote{}
+/*
+var DposVote = Vote{
+ DelegateVoters: make(map[string]map[string]bool),
+ VoterDelegates: make(map[string]map[string]bool),
+ DelegateName: make(map[string]string),
+ NameDelegate: make(map[string]string),
+ HashHeightInvalidVote: make(map[bc.Hash]uint64),
+ AddressBalances: make(map[string]uint64),
+ DelegateMultiaddress: make(map[string]uint64),
+}
+*/
+func newVote(blockHeight uint64, blockHash bc.Hash) (*Vote, error) {
+ vote := &Vote{
+ DelegateVoters: make(map[string]map[string]bool),
+ VoterDelegates: make(map[string]map[string]bool),
+ DelegateName: make(map[string]string),
+ NameDelegate: make(map[string]string),
+ HashHeightInvalidVote: make(map[bc.Hash]uint64),
+ AddressBalances: make(map[string]uint64),
+ DelegateMultiaddress: make(map[string]uint64),
+ }
-func (v *Vote) new(blockHeight uint64, blockHash bc.Hash) error {
- //DefaultDataDir
- v.filePath = filepath.Join(config.DefaultDataDir(), "dpos")
+ if err := vote.New(blockHeight, blockHash); err != nil {
+ return nil, err
+ }
+
+ return vote, nil
+}
+
+func (v *Vote) New(blockHeight uint64, blockHash bc.Hash) error {
+ v.filePath = filepath.Join(config.CommonConfig.RootDir, "dpos")
v.delegateFileName = filepath.Join(v.filePath, DelegateFile)
v.balanceFileName = filepath.Join(v.filePath, BalanceFile)
v.controlFileName = filepath.Join(v.filePath, ControlFile)
v.delegateMultiaddressName = filepath.Join(v.filePath, DelegateMultiAddressFile)
v.forgerFileName = filepath.Join(v.filePath, ForgerFile)
if blockHeight == 0 {
- if _, err := os.Stat(v.filePath); os.IsNotExist(err) {
- err := os.MkdirAll(v.filePath, 0700)
- if err != nil {
- //return fmt.Errorf("Could not create directory %v. %v", dir, err)
- return err
- }
+ if err := cmn.EnsureDir(v.filePath, 0700); err != nil {
+ return err
}
} else {
if err := v.load(blockHeight, blockHash); err != nil {
func (v *Vote) ProcessRegister(delegateAddress string, delegateName string, hash bc.Hash, height uint64) bool {
v.lockRegister.Lock()
defer v.lockRegister.Unlock()
- if _, ok := v.DelegateName[delegateAddress]; !ok {
+
+ if _, ok := v.DelegateName[delegateAddress]; ok {
v.AddInvalidVote(hash, height)
return false
}
-
- if _, ok := v.NameDelegate[delegateName]; !ok {
+ if _, ok := v.NameDelegate[delegateName]; ok {
v.AddInvalidVote(hash, height)
return false
}
-
v.DelegateName[delegateAddress] = delegateName
v.NameDelegate[delegateName] = delegateAddress
return true
v.AddInvalidVote(hash, height)
return false
} else {
- v.DelegateVoters[delegate][voterAddress] = true
+ voters[voterAddress] = true
+ v.DelegateVoters[delegate] = voters
}
} else {
- v.DelegateVoters[delegate][voterAddress] = true
+ voters := make(map[string]bool)
+ voters[voterAddress] = true
+ v.DelegateVoters[delegate] = voters
+ }
+ if dg, ok := v.VoterDelegates[voterAddress]; ok {
+ dg[delegate] = true
+ v.VoterDelegates[voterAddress] = dg
+ } else {
+ dg := make(map[string]bool)
+ dg[delegate] = true
+ v.VoterDelegates[voterAddress] = dg
}
- v.VoterDelegates[voterAddress][delegate] = true
}
-
return true
}
return true
}
-func (v *Vote) AddInvalidVote(hash bc.Hash, height uint64) {
- v.lockHashHeightInvalidVote.Lock()
- defer v.lockHashHeightInvalidVote.Unlock()
- v.HashHeightInvalidVote[hash] = height
-}
-
func (v *Vote) load(blockHeight uint64, blockHash bc.Hash) error {
if err := v.repairFile(blockHeight, blockHash); err != nil {
return err
}
if err := v.WriteControlFile(blockHeight, blockHash, v.controlFileName+"-temp"); err != nil {
+ v.Delete(blockHash)
return err
}
)
if err := v.ReadControlFile(&blockHeightTemp, &blockHashTemp, v.controlFileName); err != nil {
- return err
+ os.Rename(v.controlFileName, v.controlFileName+"-old")
+ os.Rename(v.controlFileName+"-temp", v.controlFileName)
+ os.Remove(v.controlFileName + "-old")
+ } else {
+ v.Delete(blockHashTemp)
}
- os.Rename(v.controlFileName, v.controlFileName+"-old")
- os.Rename(v.controlFileName+"-temp", v.controlFileName)
- os.Remove(v.controlFileName + "-old")
-
return nil
}
AddressBalances: v.AddressBalances,
DelegateMultiaddress: v.DelegateMultiaddress,
}
-
fileObj, err := os.OpenFile(v.forgerFileName+"-"+blockHash.String(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
return err
}
- fileObj, err := os.OpenFile(v.forgerFileName+"-"+v.oldBlockHash.String(), os.O_RDONLY, 0644)
+ data, err := ioutil.ReadFile(v.forgerFileName + "-" + v.oldBlockHash.String())
if err != nil {
return err
}
- var data []byte
-
- if _, err = fileObj.Read(data); err != nil {
- return err
- }
-
f := &forger{}
if err = json.Unmarshal(data, f); err != nil {
}
func (v *Vote) repairFile(blockHeight uint64, blockHash bc.Hash) error {
- return nil
+
+ cmn.EnsureDir(v.filePath, 0700)
+
+ fileName := v.controlFileName + "-temp"
+
+ var (
+ blockHeightTmp uint64
+ blockHashTmp bc.Hash
+ )
+
+ if cmn.FileExists(fileName) {
+ if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
+ return err
+ }
+ if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
+ os.Rename(fileName, v.controlFileName)
+ return nil
+ }
+ os.Remove(fileName)
+ }
+
+ fileName = v.controlFileName + "-old"
+
+ if cmn.FileExists(fileName) {
+ if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
+ return err
+ }
+ if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
+ os.Rename(fileName, v.controlFileName)
+ return nil
+ }
+ os.Remove(fileName)
+ }
+
+ fileName = v.controlFileName
+ if cmn.FileExists(fileName) {
+ if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
+ return err
+ }
+ if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
+ return nil
+ }
+ }
+
+ return fmt.Errorf("repairFile fail in %d height", blockHeightTmp)
}
func (v *Vote) GetTopDelegateInfo(minHoldBalance uint64, delegateNum uint64) []Delegate {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
var result []Delegate
+ for k, value := range v.DelegateVoters {
+ votes := uint64(0)
+ for address := range value {
+ votes += v.GetAddressBalance(address)
+ }
+ if v.GetAddressBalance(k) >= minHoldBalance {
+ result = append(result, Delegate{k, votes})
+ }
+ }
+ sort.Sort(DelegateWrapper{result, func(p, q *Delegate) bool {
+ if p.Votes < q.Votes {
+ return false
+ } else if p.Votes > q.Votes {
+ return true
+ } else {
+ if strings.Compare(p.DelegateAddress, p.DelegateAddress) >= 0 {
+ return false
+ }
+ }
+ return true
+ }})
+
+ for k := range v.DelegateName {
+ if uint64(len(result)) >= delegateNum {
+ break
+ }
+ if v.GetAddressBalance(k) < consensus.MinHoldBalance {
+ continue
+ }
+ if _, ok := v.DelegateVoters[k]; !ok {
+ result = append(result, Delegate{k, 0})
+ }
+ }
+ result = result[:delegateNum]
return result
}
+func (v *Vote) GetAddressBalance(address string) uint64 {
+
+ if votes, ok := v.AddressBalances[address]; ok {
+ return votes
+ }
+
+ return 0
+}
+
type control struct {
BlockHeight uint64 `json:"block_height"`
BlockHash bc.Hash `json:"block_hash"`
}
func (v *Vote) ReadControlFile(blockHeight *uint64, blockHash *bc.Hash, fileName string) error {
-
- fileObj, err := os.OpenFile(fileName, os.O_RDONLY, 0644)
+ data, err := ioutil.ReadFile(fileName)
if err != nil {
return err
}
-
- var data []byte
-
- if _, err = fileObj.Read(data); err != nil {
- return err
- }
-
c := &control{}
if err = json.Unmarshal(data, c); err != nil {
return nil
}
-func (v *Vote) UpdateAddressBalance(AddressBalance []AddressBalance) {
+func (v *Vote) UpdateAddressBalance(addressBalance []engine.AddressBalance) {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
+ mapBalance := make(map[string]int64)
+
+ for _, value := range addressBalance {
+ if value.Balance == 0 {
+ continue
+ }
+ mapBalance[value.Address] += value.Balance
+ }
+ for addr, balance := range mapBalance {
+ v.updateAddressBalance(addr, balance)
+ }
+}
+
+func (v *Vote) updateAddressBalance(address string, value int64) {
+ if val, ok := v.AddressBalances[address]; ok {
+ banlance := int64(val) + value
+ if banlance < 0 {
+ cmn.Exit("The balance was negative")
+ }
+ if banlance == 0 {
+ delete(v.AddressBalances, address)
+ } else {
+ v.AddressBalances[address] = uint64(banlance)
+ }
+ } else {
+ if value < 0 {
+ cmn.Exit("The balance was negative")
+ }
+ if value > 0 {
+ v.AddressBalances[address] = uint64(value)
+ }
+ }
+}
+
+func (v *Vote) AddInvalidVote(hash bc.Hash, height uint64) {
+ v.lockHashHeightInvalidVote.Lock()
+ defer v.lockHashHeightInvalidVote.Unlock()
+ v.HashHeightInvalidVote[hash] = height
+}
+func (v *Vote) DeleteInvalidVote(height uint64) {
+ v.lockHashHeightInvalidVote.Lock()
+ defer v.lockHashHeightInvalidVote.Unlock()
+ for k, value := range v.HashHeightInvalidVote {
+ if value <= height {
+ delete(v.HashHeightInvalidVote, k)
+ }
+ }
+}
+
+func (v *Vote) GetOldBlockHeight() uint64 {
+ return v.oldBlockHeight
+}
+
+func (v *Vote) GetOldBlockHash() bc.Hash {
+ return v.oldBlockHash
+}
+
+func (v *Vote) GetDelegate(name string) string {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
+ if delegate, ok := v.NameDelegate[name]; ok {
+ return delegate
+ }
+ return ""
+}
+
+func (v *Vote) GetDelegateName(address string) string {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+ if name, ok := v.DelegateName[address]; ok {
+ return name
+ }
+ return ""
+}
+
+func (v *Vote) HaveVote(voter string, delegate string) bool {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
+ if voters, ok := v.DelegateVoters[delegate]; ok {
+ if _, ok := voters[voter]; ok {
+ return true
+ }
+ }
+
+ return false
+}
+func (v *Vote) HaveDelegate(name string, delegate string) bool {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
+ if n, ok := v.DelegateName[delegate]; ok {
+ if n == name {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (v *Vote) GetVotedDelegates(voter string) []string {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+ var results []string
+ if delegates, ok := v.VoterDelegates[voter]; ok {
+ for delegate, _ := range delegates {
+ results = append(results, delegate)
+ }
+ }
+ return results
+}
+
+func (v *Vote) ListDelegates() map[string]string {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+ return v.NameDelegate
+}
+
+func (v *Vote) GetDelegateVotes(delegate string) uint64 {
+ votes := uint64(0)
+ if voters, ok := v.DelegateVoters[delegate]; ok {
+ for voter := range voters {
+ votes += v.GetAddressBalance(voter)
+ }
+ }
+ return votes
+}
+
+func (v *Vote) GetDelegateVoters(delegate string) []string {
+ v.lockVoter.Lock()
+ defer v.lockVoter.Unlock()
+
+ var result []string
+
+ if voters, ok := v.DelegateVoters[delegate]; ok {
+ for voter := range voters {
+ result = append(result, voter)
+ }
+ }
+
+ return result
}
-package consensus
+package dpos
import (
"github.com/vapor/crypto/ed25519/chainkd"
chainjson "github.com/vapor/encoding/json"
+ "github.com/vapor/protocol/vm"
)
// serflag variables for input types.
DataType() uint8
}
+type DposMsg struct {
+ Type vm.Op
+ Data []byte
+}
+
// DELEGATE_IDS PUBKEY SIG(block.time)
type DelegateInfoList struct {
- Delegate DelegateInfo
- Xpub chainkd.XPub
- SigTime []chainjson.HexBytes `json:"sig_time"`
+ Delegate DelegateInfo `json:"delegate"`
+ Xpub chainkd.XPub `json:"xpub"`
+ SigTime chainjson.HexBytes `json:"sig_time"`
}
func (d *DelegateInfoList) DataType() uint8 { return DelegateInfoType }
func (d *RegisterForgerData) DataType() uint8 { return RegisterType }
type VoteForgerData struct {
- Forgers []string `json:"Forgers"`
+ Forgers []string `json:"forgers"`
}
func (d *VoteForgerData) DataType() uint8 { return VoteType }
type CancelVoteForgerData struct {
- Forgers []string `json:"Forgers"`
+ Forgers []string `json:"forgers"`
}
func (d *CancelVoteForgerData) DataType() uint8 { return CancelVoteType }
+++ /dev/null
-package consensus
-
-import "errors"
-
-var (
- // ErrUnknownAncestor is returned when validating a block requires an ancestor
- // that is unknown.
- ErrUnknownAncestor = errors.New("unknown ancestor")
-
- // ErrPrunedAncestor is returned when validating a block requires an ancestor
- // that is known, but the state of which is not available.
- ErrPrunedAncestor = errors.New("pruned ancestor")
-
- // ErrFutureBlock is returned when a block's timestamp is in the future according
- // to the current node.
- ErrFutureBlock = errors.New("block in the future")
-
- // ErrInvalidNumber is returned if a block's number doesn't equal it's parent's
- // plus one.
- ErrInvalidNumber = errors.New("invalid block number")
-)
VoteForgerFee = 1000000 // 0.0.1 * Coin
CancelVoteForgerFee = 1000000 // 0.0.1 * Coin
MaxNumberOfVotes = 51
- MinHoldBalance = 500000000000
+ MinHoldBalance = 50000000000
)
func MoneyRange(nValue uint64) bool { return nValue >= 0 && nValue <= MaxMoney }
testDB := dbm.NewDB("testdb", "leveldb", "temp")
store := NewStore(testDB)
config.CommonConfig = config.DefaultConfig()
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
block := config.GenesisBlock()
txStatus := bc.NewTransactionStatus()
store := NewStore(testDB)
var savedBlocks []types.Block
config.CommonConfig = config.DefaultConfig()
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
for _, c := range cases {
package miner
import (
- "errors"
"sync"
"time"
- "github.com/vapor/blockchain/pseudohsm"
-
- "github.com/vapor/blockchain/txbuilder"
"github.com/vapor/config"
log "github.com/sirupsen/logrus"
"github.com/vapor/common"
"github.com/vapor/consensus"
engine "github.com/vapor/consensus/consensus"
- "github.com/vapor/consensus/consensus/dpos"
- "github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/mining"
"github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
- "github.com/vapor/protocol/vm/vmutil"
)
const (
module = "miner"
)
-var ConsensusEngine engine.Engine
-
// Miner creates blocks and searches for proof-of-work values.
type Miner struct {
sync.Mutex
}
func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash, engine engine.Engine) *Miner {
- dpos, ok := engine.(*dpos.Dpos)
- if !ok {
- log.Error("Only the dpos engine was allowed")
- return nil
- }
- dpos.Authorize(config.CommonConfig.Consensus.Dpos.Coinbase)
- c.SetConsensusEngine(dpos)
- ConsensusEngine = dpos
return &Miner{
chain: c,
accountManager: accountManager,
numWorkers: defaultNumWorkers,
updateNumWorkers: make(chan struct{}),
newBlockCh: newBlockCh,
- engine: dpos,
+ engine: engine,
}
}
-func (m *Miner) generateProof(block types.Block) (types.Proof, error) {
- var xPrv chainkd.XPrv
- if consensus.ActiveNetParams.Signer == "" {
- return types.Proof{}, errors.New("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
- sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
- pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
-
- address, _ := common.NewPeginAddressWitnessScriptHash(pubHash, &consensus.ActiveNetParams)
- control, err := vmutil.P2WPKHProgram([]byte(pubHash))
- if err != nil {
- return types.Proof{}, err
- }
- return types.Proof{Sign: sign, ControlProgram: control, Address: address.ScriptAddress()}, nil
-}
-
// generateBlocks is a worker that is controlled by the miningWorkerController.
// It is self contained in that it creates block templates and attempts to solve
// them while detecting when it is performing stale work and reacting
break out
default:
}
- delegateInfo := engine.DelegateInfo{}
- address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.ActiveNetParams)
- if err := engine.GDpos.IsMining(&delegateInfo, address, uint64(time.Now().Unix())); err != nil {
+ var (
+ delegateInfo interface{}
+ err error
+ )
+ address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.ActiveNetParams)
+ if delegateInfo, err = m.engine.IsMining(address, uint64(time.Now().Unix())); err != nil {
time.Sleep(1 * time.Second)
continue
}
time.Sleep(1 * time.Second)
continue
}
- block, err = m.engine.Seal(m.chain, block)
- if err != nil {
- log.Errorf("Seal, %v", err)
- continue
- }
- m.chain.SetConsensusEngine(m.engine)
+
if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
log.WithFields(log.Fields{
"height": block.BlockHeader.Height,
} else {
log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
}
- // confirm block
- //m.sendConfirmTx(block.Height - 1)
- time.Sleep(time.Duration(config.CommonConfig.Consensus.Dpos.Period) * time.Second)
+ time.Sleep(time.Duration(config.CommonConfig.Consensus.Period) * time.Second)
}
m.workerWg.Done()
}
-func (m *Miner) sendConfirmTx(height uint64) error {
- // 找到utxo
- var assetID bc.AssetID
- assetID.UnmarshalText([]byte("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
- // 生成dpos交易
- dpos := account.DopsAction{
- Accounts: m.accountManager,
- From: config.CommonConfig.Consensus.Dpos.Coinbase,
- Fee: 100000000,
- TxType: 6,
- Height: height,
- }
- dpos.AssetId = &assetID
- builder := txbuilder.NewBuilder(time.Now())
- if err := dpos.Build(nil, builder); err != nil {
- return err
- }
- // 签名
- tmpl, _, err := builder.Build()
- if err != nil {
- return err
- }
-
- var xprv chainkd.XPrv
- xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
- if err := pseudohsm.SignWithKey(tmpl, xprv); err != nil {
- return err
- }
-
- if err := txbuilder.FinalizeTx(nil, m.chain, tmpl.Transaction); err != nil {
- return err
- }
-
- return nil
-}
-
// miningWorkerController launches the worker goroutines that are used to
// generate block templates and solve them. It also provides the ability to
// dynamically adjust the number of running worker goroutines.
"strconv"
"time"
+ "github.com/vapor/protocol/vm"
+
"github.com/vapor/common"
log "github.com/sirupsen/logrus"
"github.com/vapor/config"
"github.com/vapor/consensus"
engine "github.com/vapor/consensus/consensus"
+ dpos "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/errors"
"github.com/vapor/protocol"
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the provided address. When the address
// is nil, the coinbase transaction will instead be redeemable by anyone.
-func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeight uint64, delegateInfo engine.DelegateInfo, timestamp uint64) (tx *types.Tx, err error) {
+func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeight uint64, delegateInfo interface{}, timestamp uint64) (tx *types.Tx, err error) {
//amount += consensus.BlockSubsidy(blockHeight)
arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
var script []byte
- address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.ActiveNetParams)
+ address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.ActiveNetParams)
redeemContract := address.ScriptAddress()
script, _ = vmutil.P2WPKHProgram(redeemContract)
return nil, err
}
txData.SerializedSize = uint64(len(byteData))
-
- delegates := engine.DelegateInfoList{}
- delegates.Delegate = delegateInfo
+ delegates := dpos.DelegateInfoList{}
+ if delegateInfo != nil {
+ tmp := delegateInfo.(*dpos.DelegateInfo)
+ delegates.Delegate = *tmp
+ }
var xPrv chainkd.XPrv
- if config.CommonConfig.Consensus.Dpos.XPrv == "" {
+ if config.CommonConfig.Consensus.XPrv == "" {
return nil, errors.New("Signer is empty")
}
- xPrv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
+ xPrv.UnmarshalText([]byte(config.CommonConfig.Consensus.XPrv))
buf := [8]byte{}
binary.LittleEndian.PutUint64(buf[:], timestamp)
- delegates.SigTime = xPrv.Sign(buf)
+ delegates.SigTime = xPrv.Sign(buf[:])
delegates.Xpub = xPrv.XPub()
data, err := json.Marshal(&delegates)
return nil, err
}
+ msg := dpos.DposMsg{
+ Type: vm.OP_DELEGATE,
+ Data: data,
+ }
+
+ data, err = json.Marshal(&msg)
+ if err != nil {
+ return nil, err
+ }
txData.ReferenceData = data
tx = &types.Tx{
}
// NewBlockTemplate returns a new block template that is ready to be solved
-func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager, engine engine.Engine, delegateInfo engine.DelegateInfo) (b *types.Block, err error) {
+func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager, engine engine.Engine, delegateInfo interface{}) (b *types.Block, err error) {
view := state.NewUtxoViewpoint()
txStatus := bc.NewTransactionStatus()
if err := txStatus.SetStatus(0, false); err != nil {
preBlockHash := preBlockHeader.Hash()
nextBlockHeight := preBlockHeader.Height + 1
- var xPrv chainkd.XPrv
- if config.CommonConfig.Consensus.Dpos.XPrv == "" {
- return nil, errors.New("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
- xpub, _ := xPrv.XPub().MarshalText()
-
header := types.BlockHeader{
Version: 1,
Height: nextBlockHeight,
PreviousBlockHash: preBlockHash,
Timestamp: uint64(time.Now().Unix()),
BlockCommitment: types.BlockCommitment{},
- Coinbase: xpub,
- }
-
- if err := engine.Prepare(c, &header); err != nil {
- log.Error("Failed to prepare header for mining", "err", err)
- return nil, err
}
b = &types.Block{}
}
}
- if err := engine.Finalize(c, &header, txEntries[1:]); err != nil {
- return nil, err
- }
-
b.BlockHeader = header
// creater coinbase transaction
- b.Transactions[0], err = createCoinbaseTx(accountManager, txFee, nextBlockHeight, delegateInfo, bcBlock.Timestamp)
+ b.Transactions[0], err = createCoinbaseTx(accountManager, txFee, nextBlockHeight, delegateInfo, b.Timestamp)
if err != nil {
return nil, errors.Wrap(err, "fail on createCoinbaseTx")
}
cfg "github.com/vapor/config"
"github.com/vapor/consensus"
engine "github.com/vapor/consensus/consensus"
- "github.com/vapor/consensus/consensus/dpos"
+ dpos "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/env"
maxNewBlockChSize = 1024
)
-var consensusEngine engine.Engine
-
type Node struct {
cmn.BaseService
miningEnable bool
newBlockCh chan *bc.Hash
+
+ engine engine.Engine
}
func NewNode(config *cfg.Config) *Node {
tokenDB := dbm.NewDB("accesstoken", config.DBBackend, config.DBDir())
accessTokens := accesstoken.NewStore(tokenDB)
+ var engine engine.Engine
+ switch config.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
+
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ chain, err := protocol.NewChain(store, txPool, engine)
if err != nil {
cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
}
}
if !config.Wallet.Disable {
- address, err := common.DecodeAddress(config.Consensus.Dpos.Coinbase, &consensus.ActiveNetParams)
+ address, err := common.DecodeAddress(config.Consensus.Coinbase, &consensus.ActiveNetParams)
if err != nil {
cmn.Exit(cmn.Fmt("DecodeAddress: %v", err))
}
}()
}
+ switch config.Consensus.Type {
+ case "dpos":
+ initDpos(chain, config)
+ }
+
node := &Node{
config: config,
syncManager: syncManager,
newBlockCh: newBlockCh,
notificationMgr: notificationMgr,
+ engine: engine,
}
- //node.cpuMiner = cpuminer.NewCPUMiner(chain, accounts, txPool, newBlockCh)
- consensusEngine = createConsensusEngine(config, store)
- node.miner = miner.NewMiner(chain, accounts, txPool, newBlockCh, consensusEngine)
-
+ node.miner = miner.NewMiner(chain, accounts, txPool, newBlockCh, engine)
node.BaseService = *cmn.NewBaseService(nil, "Node", node)
return node
}
func (n *Node) OnStop() {
+ if err := n.engine.Finish(); err != nil {
+ log.Errorf("OnStop: %v", err)
+ }
+
n.notificationMgr.Shutdown()
n.notificationMgr.WaitForShutdown()
n.BaseService.OnStop()
cmn.Exit(cmn.Fmt("invalid consensus file: %v", err))
}
- for _, v := range config.Consensus.Dpos.SelfVoteSigners {
+ for _, v := range config.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.ActiveNetParams)
if err != nil {
cmn.Exit(cmn.Fmt("Address resolution failed: %v", err))
}
- config.Consensus.Dpos.Signers = append(config.Consensus.Dpos.Signers, address)
+ config.Consensus.Signers = append(config.Consensus.Signers, address)
}
}
}
-func createConsensusEngine(config *cfg.Config, store protocol.Store) engine.Engine {
- if config.Consensus.Dpos != nil {
- return dpos.New(config.Consensus.Dpos, store)
- } else {
- return nil
+func initDpos(chain *protocol.Chain, config *cfg.Config) {
+ header := chain.BestBlockHeader()
+ height := header.Height
+ hash := header.Hash()
+ maxSignerCount := config.Consensus.MaxSignerCount
+ period := config.Consensus.Period
+ if err := dpos.GDpos.Init(chain, maxSignerCount, period, height, hash); err != nil {
+ cmn.Exit(cmn.Fmt("initVote: Dpos new: %v", err))
}
-}
-func GetConsensusEngine() engine.Engine {
- return consensusEngine
+ if height > 0 {
+ oldBlockHeight := dpos.GDpos.GetOldBlockHeight()
+ oldBlockHash := dpos.GDpos.GetOldBlockHash()
+ if err := chain.RepairDPoSData(oldBlockHeight, oldBlockHash); err != nil {
+ cmn.Exit(cmn.Fmt("initVote failed: %v", err))
+ }
+ }
}
Nonce uint64 `protobuf:"varint,7,opt,name=nonce" json:"nonce,omitempty"`
Bits uint64 `protobuf:"varint,8,opt,name=bits" json:"bits,omitempty"`
TransactionStatus *TransactionStatus `protobuf:"bytes,9,opt,name=transaction_status,json=transactionStatus" json:"transaction_status,omitempty"`
- Proof *Proof `protobuf:"bytes,10,opt,name=Proof" json:"Proof,omitempty"`
- Extra []byte `protobuf:"bytes,11,opt,name=extra,proto3" json:"extra,omitempty"`
- Coinbase []byte `protobuf:"bytes,12,opt,name=coinbase,proto3" json:"coinbase,omitempty"`
}
func (m *BlockHeader) Reset() { *m = BlockHeader{} }
return nil
}
-func (m *BlockHeader) GetProof() *Proof {
- if m != nil {
- return m.Proof
- }
- return nil
-}
-
-func (m *BlockHeader) GetExtra() []byte {
- if m != nil {
- return m.Extra
- }
- return nil
-}
-
-func (m *BlockHeader) GetCoinbase() []byte {
- if m != nil {
- return m.Coinbase
- }
- return nil
-}
-
type TxHeader struct {
Version uint64 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
SerializedSize uint64 `protobuf:"varint,2,opt,name=serialized_size,json=serializedSize" json:"serialized_size,omitempty"`
Data *Hash `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"`
TimeRange uint64 `protobuf:"varint,4,opt,name=time_range,json=timeRange" json:"time_range,omitempty"`
ResultIds []*Hash `protobuf:"bytes,5,rep,name=result_ids,json=resultIds" json:"result_ids,omitempty"`
+ Side bool `protobuf:"varint,6,opt,name=side" json:"side,omitempty"`
}
func (m *TxHeader) Reset() { *m = TxHeader{} }
return nil
}
+func (m *TxHeader) GetSide() bool {
+ if m != nil {
+ return m.Side
+ }
+ return false
+}
+
type TxVerifyResult struct {
StatusFail bool `protobuf:"varint,1,opt,name=status_fail,json=statusFail" json:"status_fail,omitempty"`
}
func init() { proto.RegisterFile("bc.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
- // 1098 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x57, 0xcd, 0x6e, 0xdb, 0x46,
- 0x10, 0x86, 0x24, 0xea, 0x6f, 0xa4, 0x58, 0xf6, 0xda, 0x49, 0x89, 0x20, 0x45, 0x0c, 0x02, 0x89,
- 0x53, 0x14, 0x30, 0xfc, 0x93, 0xb6, 0x97, 0x1e, 0xea, 0xc4, 0x4d, 0xa3, 0x83, 0x11, 0x63, 0x6d,
- 0xf8, 0x56, 0x10, 0x2b, 0x72, 0x25, 0x2f, 0x22, 0x71, 0xd9, 0xdd, 0xa5, 0x6a, 0xfb, 0x96, 0xb7,
- 0xe9, 0xbd, 0x87, 0x3e, 0x42, 0x4f, 0x45, 0x1f, 0xa4, 0x2f, 0x51, 0xec, 0x70, 0x29, 0x51, 0xb2,
- 0xf2, 0x87, 0xa2, 0x28, 0x02, 0xf4, 0xc6, 0x99, 0x9d, 0x9d, 0x9f, 0x6f, 0x66, 0x67, 0x86, 0xd0,
- 0x1a, 0x44, 0xbb, 0xa9, 0x92, 0x46, 0x92, 0xea, 0x20, 0x0a, 0x5e, 0x80, 0xf7, 0x92, 0xe9, 0x4b,
- 0xb2, 0x06, 0xd5, 0xe9, 0x9e, 0x5f, 0xd9, 0xae, 0x3c, 0x69, 0xd0, 0xea, 0x74, 0x0f, 0xe9, 0x7d,
- 0xbf, 0xea, 0xe8, 0x7d, 0xa4, 0x0f, 0xfc, 0x9a, 0xa3, 0x0f, 0x90, 0x3e, 0xf4, 0x3d, 0x47, 0x1f,
- 0x06, 0xdf, 0x42, 0xf3, 0x54, 0xc9, 0x91, 0x62, 0x13, 0xf2, 0x39, 0xc0, 0x74, 0x12, 0x4e, 0xb9,
- 0xd2, 0x42, 0x26, 0xa8, 0xd2, 0xa3, 0xed, 0xe9, 0xe4, 0x22, 0x67, 0x10, 0x02, 0x5e, 0x24, 0x63,
- 0x8e, 0xba, 0xbb, 0x14, 0xbf, 0x83, 0x3e, 0x34, 0x8f, 0xb4, 0xe6, 0xa6, 0x7f, 0xfc, 0x8f, 0x1d,
- 0x39, 0x81, 0x0e, 0xaa, 0x3a, 0x9a, 0xc8, 0x2c, 0x31, 0xe4, 0x31, 0xb4, 0x98, 0x25, 0x43, 0x11,
- 0xa3, 0xd2, 0xce, 0x41, 0x67, 0x77, 0x10, 0xed, 0x3a, 0x6b, 0xb4, 0x89, 0x87, 0xfd, 0x98, 0xdc,
- 0x83, 0x06, 0xc3, 0x1b, 0x68, 0xca, 0xa3, 0x8e, 0x0a, 0x46, 0xd0, 0x43, 0xd9, 0x63, 0x3e, 0x14,
- 0x89, 0x30, 0x36, 0x80, 0xaf, 0x61, 0x5d, 0x68, 0x9d, 0xb1, 0x24, 0xe2, 0x61, 0x9a, 0xc7, 0x5c,
- 0x56, 0xed, 0x60, 0xa0, 0xbd, 0x42, 0xa8, 0xc0, 0xe5, 0x01, 0x78, 0x31, 0x33, 0x0c, 0x0d, 0x74,
- 0x0e, 0x5a, 0x56, 0xd6, 0x42, 0x4f, 0x91, 0x1b, 0x8c, 0xa1, 0x73, 0xc1, 0xc6, 0x19, 0x3f, 0x93,
- 0x99, 0x8a, 0x38, 0xb9, 0x0f, 0x35, 0xc5, 0x87, 0x4e, 0xef, 0x5c, 0xd6, 0x32, 0xc9, 0x23, 0xa8,
- 0x4f, 0xad, 0xa8, 0xd3, 0xd4, 0x9b, 0x05, 0x94, 0xc7, 0x4c, 0xf3, 0x53, 0x72, 0x1f, 0x5a, 0xa9,
- 0xd4, 0xe8, 0x33, 0xe2, 0xe5, 0xd1, 0x19, 0x1d, 0xfc, 0x04, 0xeb, 0x68, 0xed, 0x98, 0x6b, 0x23,
- 0x12, 0x86, 0x71, 0xfd, 0xcb, 0x26, 0x7f, 0x84, 0xfa, 0xa9, 0x92, 0x72, 0x68, 0x0b, 0x40, 0x8b,
- 0x51, 0x5e, 0x19, 0x5d, 0x8a, 0xdf, 0xe4, 0x31, 0xac, 0x45, 0x32, 0x31, 0x4a, 0x8e, 0x1d, 0x5a,
- 0xae, 0x3c, 0x96, 0xb8, 0xc4, 0x87, 0x26, 0x8b, 0x63, 0xc5, 0xb5, 0x46, 0xfd, 0x5d, 0x5a, 0x90,
- 0xc1, 0x9b, 0x1a, 0xac, 0x3f, 0xbb, 0x36, 0x72, 0xf2, 0x6c, 0x2c, 0xa3, 0xd7, 0x2f, 0x39, 0x8b,
- 0xb9, 0xb2, 0xe2, 0x8b, 0x75, 0x58, 0x90, 0x36, 0xdf, 0x97, 0x5c, 0x8c, 0x2e, 0x67, 0xf9, 0xce,
- 0x29, 0xf2, 0x14, 0x36, 0x52, 0xc5, 0xa7, 0x42, 0x66, 0x3a, 0x1c, 0x58, 0x4d, 0xb6, 0x70, 0x6a,
- 0x4b, 0x90, 0xf4, 0x0a, 0x11, 0xb4, 0xd5, 0x8f, 0xc9, 0x03, 0x68, 0x1b, 0x31, 0xe1, 0xda, 0xb0,
- 0x49, 0x8a, 0xb5, 0xe8, 0xd1, 0x39, 0x83, 0x7c, 0x05, 0x1b, 0x46, 0xb1, 0x44, 0xb3, 0xc8, 0x02,
- 0xa1, 0x43, 0x25, 0xa5, 0xf1, 0xeb, 0x4b, 0x3a, 0xd7, 0xcb, 0x22, 0x54, 0x4a, 0x43, 0xbe, 0x83,
- 0xcf, 0x4a, 0xbc, 0x50, 0x1b, 0x66, 0x32, 0x1d, 0x5e, 0x32, 0x7d, 0xe9, 0x37, 0x96, 0x2e, 0xdf,
- 0x2d, 0x09, 0x9e, 0xa1, 0x1c, 0x3e, 0xea, 0x2d, 0xa8, 0x27, 0x32, 0x89, 0xb8, 0xdf, 0x44, 0x97,
- 0x72, 0xc2, 0xe2, 0x3f, 0x10, 0x46, 0xfb, 0x2d, 0x64, 0xe2, 0x37, 0x39, 0x06, 0x72, 0xdb, 0x96,
- 0xdf, 0x46, 0x33, 0x77, 0xad, 0x99, 0xf3, 0x65, 0x03, 0x74, 0xe3, 0x96, 0xcd, 0xe0, 0xcf, 0x1a,
- 0x74, 0xfe, 0x87, 0xff, 0xbf, 0x82, 0x9f, 0x3c, 0x74, 0x2f, 0xcc, 0x07, 0xbc, 0xd8, 0x76, 0xdd,
- 0x48, 0x0e, 0xa9, 0x7b, 0x79, 0x5b, 0x50, 0xe7, 0x57, 0x46, 0x31, 0xbf, 0x83, 0x6f, 0x27, 0x27,
- 0xec, 0xa3, 0x8d, 0xa4, 0x48, 0x06, 0x4c, 0x73, 0xbf, 0x8b, 0x07, 0x33, 0x3a, 0xf8, 0xb5, 0x02,
- 0xad, 0xf3, 0xab, 0xf7, 0xa6, 0x73, 0x07, 0x7a, 0x9a, 0x2b, 0xc1, 0xc6, 0xe2, 0x86, 0xc7, 0xa1,
- 0x16, 0x37, 0xdc, 0xe5, 0x75, 0x6d, 0xce, 0x3e, 0x13, 0x37, 0x7c, 0xd6, 0x03, 0x6b, 0xab, 0x7a,
- 0xa0, 0x9d, 0x1c, 0x36, 0x6d, 0xa1, 0x62, 0xc9, 0x88, 0x97, 0x13, 0x49, 0x2d, 0x83, 0xec, 0x00,
- 0x28, 0xae, 0xb3, 0xb1, 0x6d, 0xe6, 0xda, 0xaf, 0x6f, 0xd7, 0x16, 0x54, 0xb4, 0xf3, 0xb3, 0x7e,
- 0xac, 0x83, 0x7d, 0x58, 0x3b, 0xbf, 0xba, 0xe0, 0x4a, 0x0c, 0xaf, 0x29, 0x32, 0xc9, 0x43, 0xe8,
- 0xb8, 0x04, 0x0e, 0x99, 0x18, 0xa3, 0xfb, 0x2d, 0x0a, 0x39, 0xeb, 0x05, 0x13, 0xe3, 0x60, 0x08,
- 0x1b, 0xb7, 0x30, 0x7e, 0x47, 0xc0, 0xdf, 0xc0, 0x9d, 0x29, 0xea, 0x2f, 0x72, 0x55, 0x45, 0x6f,
- 0x08, 0xe6, 0x6a, 0xc1, 0x34, 0xed, 0xe6, 0x82, 0xee, 0x89, 0xfc, 0x51, 0x81, 0xda, 0x49, 0x76,
- 0x45, 0xbe, 0x80, 0xa6, 0xc6, 0x4e, 0xaf, 0xfd, 0x0a, 0x5e, 0xc5, 0x96, 0x5a, 0x9a, 0x00, 0xb4,
- 0x38, 0x27, 0x8f, 0xa0, 0x99, 0x96, 0x9a, 0xe2, 0xd2, 0x98, 0x29, 0xce, 0xc8, 0x0f, 0xb0, 0xf5,
- 0xb3, 0x30, 0x09, 0xd7, 0x3a, 0x8c, 0xe7, 0x5d, 0xdd, 0xf6, 0x49, 0xab, 0x7e, 0x6b, 0xa6, 0xbe,
- 0xd4, 0xf2, 0xe9, 0xa6, 0xbb, 0x51, 0xe2, 0x69, 0xf2, 0x25, 0x6c, 0x14, 0x8a, 0x98, 0x1a, 0x65,
- 0x13, 0x9e, 0x18, 0xed, 0x7b, 0xdb, 0xb5, 0x27, 0x5d, 0xba, 0xee, 0x0e, 0x8e, 0x0a, 0x7e, 0x20,
- 0xa1, 0xf5, 0xdc, 0x15, 0x0b, 0xf9, 0x1e, 0x36, 0x57, 0x78, 0xe0, 0x06, 0xca, 0x6a, 0x07, 0xc8,
- 0x6d, 0x07, 0xec, 0x6b, 0x66, 0x6a, 0x20, 0x8c, 0x62, 0xea, 0xda, 0x8d, 0x81, 0x39, 0x23, 0x78,
- 0x53, 0x81, 0xc6, 0xab, 0xcc, 0xa4, 0x99, 0x21, 0x3b, 0xd0, 0xc8, 0x31, 0x72, 0x26, 0x6e, 0x41,
- 0xe8, 0x8e, 0xc9, 0x53, 0xe8, 0xb9, 0x39, 0x12, 0xbe, 0x03, 0xc9, 0x15, 0xb3, 0x46, 0xaa, 0x58,
- 0x24, 0x6c, 0xec, 0x66, 0x59, 0x41, 0x06, 0xaf, 0x00, 0x28, 0x37, 0x42, 0x71, 0x8b, 0xc1, 0x87,
- 0xbb, 0x51, 0x52, 0x58, 0x5d, 0x54, 0xf8, 0x5b, 0x15, 0x5a, 0x7d, 0xb7, 0x2e, 0xd8, 0x32, 0xc7,
- 0x4e, 0x91, 0xf7, 0x9a, 0xe5, 0x71, 0xdc, 0xc6, 0x33, 0xec, 0x2f, 0x1f, 0x38, 0x94, 0xdf, 0x92,
- 0x96, 0xda, 0x47, 0xa6, 0xe5, 0x04, 0xfc, 0x59, 0x59, 0xe0, 0x46, 0x15, 0xcf, 0x56, 0x22, 0x7c,
- 0xaa, 0x9d, 0x83, 0xcd, 0x99, 0x03, 0xf3, 0x6d, 0x89, 0xde, 0x2b, 0x4a, 0x66, 0x69, 0x8b, 0x5a,
- 0x59, 0x65, 0xf5, 0xd5, 0x55, 0x56, 0x46, 0xae, 0xb1, 0x88, 0xdc, 0xef, 0x15, 0xa8, 0x9f, 0xa5,
- 0x3c, 0x89, 0xc9, 0x1e, 0xf4, 0x74, 0xca, 0x13, 0x13, 0x4a, 0xac, 0x8e, 0xf9, 0xc2, 0x37, 0xc7,
- 0xee, 0x0e, 0x0a, 0xe4, 0xd5, 0xd3, 0x8f, 0xdf, 0x06, 0x4c, 0xf5, 0x23, 0x81, 0x59, 0x19, 0x49,
- 0xed, 0xfd, 0x91, 0x78, 0x8b, 0x91, 0xfc, 0x55, 0x81, 0xfa, 0xf3, 0x31, 0x13, 0x93, 0x4f, 0x3d,
- 0x12, 0x12, 0x40, 0xf7, 0x94, 0x8f, 0x44, 0xe2, 0xae, 0xb8, 0xac, 0x2e, 0xf0, 0x82, 0x5f, 0xaa,
- 0xe0, 0x1d, 0xa7, 0x52, 0x7f, 0xf2, 0xc1, 0x12, 0xf0, 0xcc, 0x75, 0xca, 0x71, 0xa1, 0xb8, 0x43,
- 0xf1, 0xdb, 0xf2, 0x86, 0x4a, 0x4e, 0xb0, 0x56, 0xdb, 0x14, 0xbf, 0xed, 0x7f, 0x8a, 0x91, 0xb8,
- 0x09, 0xb4, 0x69, 0xd5, 0x48, 0x3b, 0x8b, 0xb5, 0x61, 0xaf, 0xb9, 0xdb, 0x03, 0x72, 0xc2, 0xde,
- 0xc4, 0xf9, 0xd8, 0xce, 0x6f, 0xda, 0xef, 0x41, 0x03, 0xff, 0xd6, 0x0e, 0xff, 0x0e, 0x00, 0x00,
- 0xff, 0xff, 0xbc, 0x6e, 0xdc, 0xf9, 0xb9, 0x0d, 0x00, 0x00,
+ // 1070 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x57, 0xcd, 0x6e, 0x1b, 0xb7,
+ 0x13, 0x87, 0x56, 0xab, 0xaf, 0x91, 0x6c, 0xd9, 0xb4, 0x93, 0xff, 0x22, 0xc8, 0x1f, 0x35, 0x16,
+ 0x48, 0x9c, 0xa2, 0x80, 0xe1, 0x8f, 0xb4, 0xbd, 0xf4, 0x50, 0x27, 0x6e, 0x1a, 0x1d, 0x8c, 0x18,
+ 0xb4, 0xe1, 0x5b, 0xb1, 0xa0, 0xb4, 0x94, 0x4c, 0x44, 0x5a, 0x6e, 0x49, 0xae, 0x6a, 0xfb, 0x96,
+ 0xb7, 0xe9, 0x1b, 0xf4, 0x11, 0x72, 0xea, 0x93, 0xf4, 0x15, 0x7a, 0x28, 0x38, 0xcb, 0x95, 0x56,
+ 0xb2, 0xf2, 0x85, 0xa2, 0x28, 0x02, 0xf4, 0xc6, 0x19, 0x0e, 0x7f, 0x33, 0xf3, 0xe3, 0xec, 0x0c,
+ 0x17, 0x9a, 0xfd, 0xc1, 0x5e, 0xaa, 0xa4, 0x91, 0xc4, 0xeb, 0x0f, 0xc2, 0x17, 0xe0, 0xbf, 0x64,
+ 0xfa, 0x8a, 0xac, 0x83, 0x37, 0xdd, 0x0f, 0x2a, 0x3b, 0x95, 0x27, 0x75, 0xea, 0x4d, 0xf7, 0x51,
+ 0x3e, 0x08, 0x3c, 0x27, 0x1f, 0xa0, 0x7c, 0x18, 0x54, 0x9d, 0x7c, 0x88, 0xf2, 0x51, 0xe0, 0x3b,
+ 0xf9, 0x28, 0xfc, 0x0e, 0x1a, 0x67, 0x4a, 0x8e, 0x14, 0x9b, 0x90, 0xff, 0x03, 0x4c, 0x27, 0xd1,
+ 0x94, 0x2b, 0x2d, 0x64, 0x82, 0x90, 0x3e, 0x6d, 0x4d, 0x27, 0x97, 0xb9, 0x82, 0x10, 0xf0, 0x07,
+ 0x32, 0xe6, 0x88, 0xdd, 0xa1, 0xb8, 0x0e, 0x7b, 0xd0, 0x38, 0xd6, 0x9a, 0x9b, 0xde, 0xc9, 0xdf,
+ 0x0e, 0xe4, 0x14, 0xda, 0x08, 0x75, 0x3c, 0x91, 0x59, 0x62, 0xc8, 0x63, 0x68, 0x32, 0x2b, 0x46,
+ 0x22, 0x46, 0xd0, 0xf6, 0x61, 0x7b, 0xaf, 0x3f, 0xd8, 0x73, 0xde, 0x68, 0x03, 0x37, 0x7b, 0x31,
+ 0xb9, 0x0f, 0x75, 0x86, 0x27, 0xd0, 0x95, 0x4f, 0x9d, 0x14, 0x8e, 0xa0, 0x8b, 0xb6, 0x27, 0x7c,
+ 0x28, 0x12, 0x61, 0x6c, 0x02, 0xdf, 0xc0, 0x86, 0xd0, 0x3a, 0x63, 0xc9, 0x80, 0x47, 0x69, 0x9e,
+ 0x73, 0x19, 0xda, 0xd1, 0x40, 0xbb, 0x85, 0x51, 0xc1, 0xcb, 0x43, 0xf0, 0x63, 0x66, 0x18, 0x3a,
+ 0x68, 0x1f, 0x36, 0xad, 0xad, 0xa5, 0x9e, 0xa2, 0x36, 0x1c, 0x43, 0xfb, 0x92, 0x8d, 0x33, 0x7e,
+ 0x2e, 0x33, 0x35, 0xe0, 0xe4, 0x01, 0x54, 0x15, 0x1f, 0x3a, 0xdc, 0xb9, 0xad, 0x55, 0x92, 0x47,
+ 0x50, 0x9b, 0x5a, 0x53, 0x87, 0xd4, 0x9d, 0x25, 0x94, 0xe7, 0x4c, 0xf3, 0x5d, 0xf2, 0x00, 0x9a,
+ 0xa9, 0xd4, 0x18, 0x33, 0xf2, 0xe5, 0xd3, 0x99, 0x1c, 0xfe, 0x0c, 0x1b, 0xe8, 0xed, 0x84, 0x6b,
+ 0x23, 0x12, 0x86, 0x79, 0xfd, 0xc3, 0x2e, 0x7f, 0x82, 0xda, 0x99, 0x92, 0x72, 0x68, 0x0b, 0x40,
+ 0x8b, 0x51, 0x5e, 0x19, 0x1d, 0x8a, 0x6b, 0xf2, 0x18, 0xd6, 0x07, 0x32, 0x31, 0x4a, 0x8e, 0x1d,
+ 0x5b, 0xae, 0x3c, 0x96, 0xb4, 0x24, 0x80, 0x06, 0x8b, 0x63, 0xc5, 0xb5, 0x46, 0xfc, 0x0e, 0x2d,
+ 0xc4, 0xf0, 0x4d, 0x15, 0x36, 0x9e, 0xdd, 0x18, 0x39, 0x79, 0x36, 0x96, 0x83, 0xd7, 0x2f, 0x39,
+ 0x8b, 0xb9, 0xb2, 0xe6, 0x8b, 0x75, 0x58, 0x88, 0xf6, 0xbe, 0xaf, 0xb8, 0x18, 0x5d, 0xcd, 0xee,
+ 0x3b, 0x97, 0xc8, 0x53, 0xd8, 0x4c, 0x15, 0x9f, 0x0a, 0x99, 0xe9, 0xa8, 0x6f, 0x91, 0x6c, 0xe1,
+ 0x54, 0x97, 0x28, 0xe9, 0x16, 0x26, 0xe8, 0xab, 0x17, 0x93, 0x87, 0xd0, 0x32, 0x62, 0xc2, 0xb5,
+ 0x61, 0x93, 0x14, 0x6b, 0xd1, 0xa7, 0x73, 0x05, 0xf9, 0x1a, 0x36, 0x8d, 0x62, 0x89, 0x66, 0x03,
+ 0x4b, 0x84, 0x8e, 0x94, 0x94, 0x26, 0xa8, 0x2d, 0x61, 0x6e, 0x94, 0x4d, 0xa8, 0x94, 0x86, 0x7c,
+ 0x0f, 0xff, 0x2b, 0xe9, 0x22, 0x6d, 0x98, 0xc9, 0x74, 0x74, 0xc5, 0xf4, 0x55, 0x50, 0x5f, 0x3a,
+ 0x7c, 0xaf, 0x64, 0x78, 0x8e, 0x76, 0xf8, 0x51, 0x6f, 0x43, 0x2d, 0x91, 0xc9, 0x80, 0x07, 0x0d,
+ 0x0c, 0x29, 0x17, 0x2c, 0xff, 0x7d, 0x61, 0x74, 0xd0, 0x44, 0x25, 0xae, 0xc9, 0x09, 0x90, 0xbb,
+ 0xbe, 0x82, 0x16, 0xba, 0xb9, 0x67, 0xdd, 0x5c, 0x2c, 0x3b, 0xa0, 0x9b, 0x77, 0x7c, 0x86, 0x7f,
+ 0x7a, 0xd0, 0xfe, 0x8f, 0xfe, 0x7f, 0x8d, 0xfe, 0xb7, 0x15, 0x68, 0x5e, 0x5c, 0x7f, 0x90, 0xfb,
+ 0x5d, 0xe8, 0x6a, 0xae, 0x04, 0x1b, 0x8b, 0x5b, 0x1e, 0x47, 0x5a, 0xdc, 0x72, 0x77, 0x09, 0xeb,
+ 0x73, 0xf5, 0xb9, 0xb8, 0xe5, 0xb3, 0x86, 0x55, 0x5d, 0xd5, 0xb0, 0x6c, 0x9b, 0xb7, 0x1c, 0x47,
+ 0x8a, 0x25, 0x23, 0x5e, 0x66, 0x9d, 0x5a, 0x05, 0xd9, 0x05, 0x50, 0x5c, 0x67, 0x63, 0xdb, 0x79,
+ 0x75, 0x50, 0xdb, 0xa9, 0x2e, 0x40, 0xb4, 0xf2, 0xbd, 0x5e, 0xac, 0xf3, 0x76, 0x10, 0x73, 0x24,
+ 0xb5, 0x49, 0x71, 0x1d, 0x1e, 0xc0, 0xfa, 0xc5, 0xf5, 0x25, 0x57, 0x62, 0x78, 0x43, 0xd1, 0x90,
+ 0x7c, 0x01, 0x6d, 0x77, 0x03, 0x43, 0x26, 0xc6, 0x98, 0x52, 0x93, 0x42, 0xae, 0x7a, 0xc1, 0xc4,
+ 0x38, 0x1c, 0xc2, 0xe6, 0x1d, 0x92, 0xde, 0x43, 0xc2, 0xb7, 0xb0, 0x36, 0x45, 0xfc, 0x82, 0x6c,
+ 0x0f, 0x23, 0x24, 0x48, 0xf6, 0x82, 0x6b, 0xda, 0xc9, 0x0d, 0x1d, 0xc9, 0xbf, 0x57, 0xa0, 0x7a,
+ 0x9a, 0x5d, 0x93, 0x2f, 0xa1, 0xa1, 0xb1, 0x55, 0xeb, 0xa0, 0x82, 0x47, 0xb1, 0x27, 0x96, 0x5a,
+ 0x38, 0x2d, 0xf6, 0xc9, 0x23, 0x68, 0xa4, 0xa5, 0xae, 0xb6, 0x34, 0x27, 0x8a, 0x3d, 0xf2, 0x23,
+ 0x6c, 0xff, 0x22, 0x4c, 0xc2, 0xb5, 0x8e, 0xe2, 0x79, 0x5b, 0xb6, 0x8d, 0xce, 0xc2, 0x6f, 0xcf,
+ 0xe0, 0x4b, 0x3d, 0x9b, 0x6e, 0xb9, 0x13, 0x25, 0x9d, 0x26, 0x5f, 0xc1, 0x66, 0x01, 0xc4, 0xd4,
+ 0x28, 0x9b, 0xf0, 0xc4, 0xe8, 0xc0, 0xdf, 0xa9, 0x3e, 0xe9, 0xd0, 0x0d, 0xb7, 0x71, 0x5c, 0xe8,
+ 0x43, 0x09, 0xcd, 0xe7, 0x52, 0x24, 0x7d, 0xa6, 0x39, 0xf9, 0x01, 0xb6, 0x56, 0x44, 0xe0, 0x26,
+ 0xc2, 0xea, 0x00, 0xc8, 0xdd, 0x00, 0xec, 0xe7, 0xc8, 0x54, 0x5f, 0x18, 0xc5, 0xd4, 0x8d, 0xeb,
+ 0xe3, 0x73, 0x45, 0xf8, 0xa6, 0x02, 0xf5, 0x57, 0x99, 0x49, 0x33, 0x43, 0x76, 0xa1, 0x9e, 0x73,
+ 0xe4, 0x5c, 0xdc, 0xa1, 0xd0, 0x6d, 0x93, 0xa7, 0xd0, 0x75, 0x83, 0x20, 0x7a, 0x0f, 0x93, 0x2b,
+ 0x86, 0x85, 0x54, 0xb1, 0x48, 0xd8, 0xd8, 0x0d, 0xa3, 0x42, 0x0c, 0x5f, 0x01, 0x50, 0x6e, 0x84,
+ 0xe2, 0x96, 0x83, 0x8f, 0x0f, 0xa3, 0x04, 0xe8, 0x2d, 0x02, 0xfe, 0xe6, 0x41, 0xb3, 0xe7, 0xe6,
+ 0xbd, 0x2d, 0x7d, 0xfc, 0xd4, 0xf3, 0x66, 0xb1, 0x3c, 0x4f, 0x5b, 0xb8, 0x87, 0x0d, 0xe2, 0x23,
+ 0xa7, 0xea, 0x3b, 0xae, 0xa5, 0xfa, 0x89, 0xd7, 0x72, 0x0a, 0xc1, 0xac, 0x2c, 0xf0, 0x49, 0x14,
+ 0xcf, 0xde, 0x34, 0xf8, 0xf9, 0xb6, 0x0f, 0xb7, 0x66, 0x01, 0xcc, 0x9f, 0x3b, 0xf4, 0x7e, 0x51,
+ 0x32, 0x4b, 0xcf, 0xa0, 0x95, 0x55, 0x56, 0x5b, 0x5d, 0x65, 0x65, 0xe6, 0xea, 0x8b, 0xcc, 0xbd,
+ 0xad, 0x40, 0xed, 0x3c, 0xe5, 0x49, 0x4c, 0xf6, 0xa1, 0xab, 0x53, 0x9e, 0x98, 0x48, 0x62, 0x75,
+ 0xcc, 0x5f, 0x6c, 0x73, 0xee, 0xd6, 0xd0, 0x20, 0xaf, 0x9e, 0x5e, 0xfc, 0x2e, 0x62, 0xbc, 0x4f,
+ 0x24, 0x66, 0x65, 0x26, 0xd5, 0x0f, 0x67, 0xe2, 0x2f, 0x66, 0xf2, 0x47, 0x05, 0x6a, 0xcf, 0xc7,
+ 0x4c, 0x4c, 0x3e, 0xf7, 0x4c, 0x48, 0x08, 0x9d, 0x33, 0x3e, 0x12, 0x89, 0x3b, 0xe2, 0x6e, 0x75,
+ 0x41, 0x17, 0xfe, 0xea, 0x81, 0x7f, 0x92, 0x4a, 0xfd, 0xd9, 0x27, 0x4b, 0xc0, 0x37, 0x37, 0x29,
+ 0xc7, 0x17, 0xc1, 0x1a, 0xc5, 0xb5, 0xd5, 0x0d, 0x95, 0x9c, 0x60, 0xad, 0xb6, 0x28, 0xae, 0xed,
+ 0x8f, 0x86, 0x91, 0x38, 0xca, 0x5b, 0xd4, 0x33, 0xd2, 0x4e, 0x77, 0x6d, 0xd8, 0x6b, 0xee, 0x06,
+ 0x79, 0x2e, 0xd8, 0x93, 0x38, 0x33, 0x5b, 0xf9, 0x49, 0xbb, 0xee, 0xd7, 0xf1, 0x77, 0xeb, 0xe8,
+ 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x94, 0x81, 0x10, 0xfb, 0x7a, 0x0d, 0x00, 0x00,
}
uint64 nonce = 7;
uint64 bits = 8;
TransactionStatus transaction_status = 9;
- Proof Proof = 10;
- bytes extra = 11;
- bytes coinbase = 12;
}
message TxHeader {
Hash data = 3;
uint64 time_range = 4;
repeated Hash result_ids = 5;
+ bool side = 6;
}
message TxVerifyResult {
mustWriteForHash(w, bh.Height)
mustWriteForHash(w, bh.PreviousBlockId)
mustWriteForHash(w, bh.Timestamp)
- //mustWriteForHash(w, bh.Coinbase)
mustWriteForHash(w, bh.TransactionsRoot)
mustWriteForHash(w, bh.TransactionStatusHash)
- mustWriteForHash(w, bh.Proof.Sign)
- mustWriteForHash(w, bh.Proof.ControlProgram)
- mustWriteForHash(w, bh.Extra)
}
// NewBlockHeader creates a new BlockHeader and populates
// its body.
-func NewBlockHeader(version, height uint64, previousBlockID *Hash, timestamp uint64, transactionsRoot, transactionStatusHash *Hash, proof *Proof, extra []byte, coinbase []byte) *BlockHeader {
+func NewBlockHeader(version, height uint64, previousBlockID *Hash, timestamp uint64, transactionsRoot, transactionStatusHash *Hash) *BlockHeader {
return &BlockHeader{
Version: version,
Height: height,
TransactionsRoot: transactionsRoot,
TransactionStatusHash: transactionStatusHash,
TransactionStatus: nil,
- Proof: proof,
- Extra: extra,
- Coinbase: coinbase,
}
}
entries := []Entry{
NewIssuance(nil, &AssetAmount{}, 0),
m,
- NewTxHeader(1, 1, 0, nil),
+ NewTxHeader(1, 1, nil, 0, nil, true),
NewOutput(&ValueSource{}, &Program{Code: []byte{1}, VmVersion: 1}, 0),
NewRetirement(&ValueSource{}, 1),
NewSpend(&Hash{}, 0),
mustWriteForHash(w, h.Version)
mustWriteForHash(w, h.TimeRange)
mustWriteForHash(w, h.ResultIds)
- mustWriteForHash(w, h.Data)
+ if h.Side {
+ mustWriteForHash(w, h.Data)
+ }
}
// NewTxHeader creates an new TxHeader.
-func NewTxHeader(version, serializedSize uint64, data *Hash, timeRange uint64, resultIDs []*Hash) *TxHeader {
+func NewTxHeader(version, serializedSize uint64, data *Hash, timeRange uint64, resultIDs []*Hash, side bool) *TxHeader {
return &TxHeader{
Version: version,
SerializedSize: serializedSize,
Data: data,
TimeRange: timeRange,
ResultIds: resultIDs,
+ Side: side,
}
}
"github.com/vapor/protocol/bc"
)
-type Proof struct {
- Sign []byte
- ControlProgram []byte
- Address []byte
-}
-
-func (p *Proof) readFrom(r *blockchain.Reader) (err error) {
- if p.Sign, err = blockchain.ReadVarstr31(r); err != nil {
- return err
- }
- if p.ControlProgram, err = blockchain.ReadVarstr31(r); err != nil {
- return err
- }
- if p.Address, err = blockchain.ReadVarstr31(r); err != nil {
- return err
- }
- return nil
-}
-
-func (p *Proof) writeTo(w io.Writer) error {
- if _, err := blockchain.WriteVarstr31(w, p.Sign); err != nil {
- return err
- }
-
- if _, err := blockchain.WriteVarstr31(w, p.ControlProgram); err != nil {
- return err
- }
- if _, err := blockchain.WriteVarstr31(w, p.Address); err != nil {
- return err
- }
- return nil
-}
-
// BlockHeader defines information about a block and is used in the Bytom
type BlockHeader struct {
Version uint64 // The version of the block.
Height uint64 // The height of the block.
PreviousBlockHash bc.Hash // The hash of the previous block.
Timestamp uint64 // The time of the block in seconds.
- Coinbase []byte
- Proof Proof
- Extra []byte
BlockCommitment
}
if bh.Timestamp, err = blockchain.ReadVarint63(r); err != nil {
return 0, err
}
- if bh.Coinbase, err = blockchain.ReadVarstr31(r); err != nil {
- return 0, err
- }
if _, err = blockchain.ReadExtensibleString(r, bh.BlockCommitment.readFrom); err != nil {
return 0, err
}
- if _, err = blockchain.ReadExtensibleString(r, bh.Proof.readFrom); err != nil {
- return 0, err
- }
- if bh.Extra, err = blockchain.ReadVarstr31(r); err != nil {
- return 0, err
- }
return
}
if _, err = blockchain.WriteVarint63(w, bh.Timestamp); err != nil {
return err
}
- if _, err := blockchain.WriteVarstr31(w, bh.Coinbase); err != nil {
- return err
- }
if _, err = blockchain.WriteExtensibleString(w, nil, bh.BlockCommitment.writeTo); err != nil {
return err
}
- if _, err = blockchain.WriteExtensibleString(w, nil, bh.Proof.writeTo); err != nil {
- return err
- }
- if _, err = blockchain.WriteVarstr31(w, bh.Extra); err != nil {
- return err
- }
return nil
}
mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
}
- h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &bc.Hash{}, tx.TimeRange, resultIDs)
+ h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &bc.Hash{}, tx.TimeRange, resultIDs, false)
return addEntry(h), h, entryMap
}
package types
import (
- "fmt"
-
"github.com/vapor/protocol/bc"
)
func NewDpos(arguments [][]byte, from, to string, sourceID bc.Hash, assetID bc.AssetID, stake, amount, sourcePos uint64, controlProgram []byte, t TxType, height uint64) *TxInput {
var vote string
- switch t {
- case LoginCandidate:
- case LogoutCandidate:
- case Delegate:
- vote = "vapor:1:event:vote"
- case UnDelegate:
- case ConfirmTx:
- vote = fmt.Sprintf("vapor:1:event:confirm:%d", height)
- }
+
sc := SpendCommitment{
AssetAmount: bc.AssetAmount{
AssetId: &assetID,
mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
}
refdatahash := hashData(tx.ReferenceData)
- h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &refdatahash, tx.TimeRange, resultIDs)
+ h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &refdatahash, tx.TimeRange, resultIDs, true)
return addEntry(h), h, entryMap
}
func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
- proof := &bc.Proof{Sign: old.Proof.Sign, ControlProgram: old.Proof.ControlProgram}
- bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, proof, old.Extra, old.Coinbase)
+ bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash)
return bc.EntryID(bh), bh
}
[]byte("00000"),
},
},
- want: testutil.MustDecodeHash("fe34dbd5da0ce3656f423fd7aad7fc7e879353174d33a6446c2ed0e3f3512101"),
+ want: testutil.MustDecodeHash("011a6b552cc8eced01c403b138c51f906d0ccd0bbdf986d2b3e0cc69a4291737"),
}, {
witnesses: [][][]byte{
{
[]byte("111111"),
},
},
- want: testutil.MustDecodeHash("0e4b4c1af18b8f59997804d69f8f66879ad5e30027346ee003ff7c7a512e5554"),
+ want: testutil.MustDecodeHash("64cef8abecac041b87110309dd9068d4935a31fb1bd1572144d11ead9da91dba"),
}, {
witnesses: [][][]byte{
{
[]byte("222222"),
},
},
- want: testutil.MustDecodeHash("0e4b4c1af18b8f59997804d69f8f66879ad5e30027346ee003ff7c7a512e5554"),
+ want: testutil.MustDecodeHash("64cef8abecac041b87110309dd9068d4935a31fb1bd1572144d11ead9da91dba"),
}}
for _, c := range cases {
const (
Binary TxType = iota
- LoginCandidate
- LogoutCandidate
- Delegate
- UnDelegate
- ConfirmTx
+ Registe
+ Vote
+ CancelVote
)
// SpendInput satisfies the TypedInput interface and represents a spend transaction.
tx.Outputs = append(tx.Outputs, to)
}
tx.SerializedSize = uint64(startSerializedSize - r.Len())
+
+ if tx.ReferenceData, err = blockchain.ReadVarstr31(r); err != nil {
+ return errors.Wrap(err, "reading transaction referenceData")
+ }
+
return nil
}
return errors.Wrapf(err, "writing tx output %d", i)
}
}
+
+ if _, err := blockchain.WriteVarstr31(w, tx.ReferenceData); err != nil {
+ return errors.Wrap(err, "writing tx ReferenceData")
+ }
+
return nil
}
import (
"encoding/json"
- "fmt"
+
+ "github.com/vapor/protocol/vm"
log "github.com/sirupsen/logrus"
"github.com/vapor/common"
"github.com/vapor/consensus"
engine "github.com/vapor/consensus/consensus"
+ dpos "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/errors"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
return c.setState(node, utxoView)
}
+func (c *Chain) consensusCheck(block *types.Block) error {
+ if err := dpos.GDpos.CheckBlockHeader(block.BlockHeader); err != nil {
+ return err
+ }
+
+ if err := dpos.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil {
+ return err
+ }
+
+ if err := dpos.GDpos.CheckBlock(*block, true); err != nil {
+ return err
+ }
+ return nil
+}
+
// SaveBlock will validate and save block into storage
func (c *Chain) saveBlock(block *types.Block) error {
bcBlock := types.MapBlock(block)
parent := c.index.GetNode(&block.PreviousBlockHash)
- if err := validation.ValidateBlock(bcBlock, parent, block, c); err != nil {
+ if err := c.consensusCheck(block); err != nil {
+ return err
+ }
+
+ if err := validation.ValidateBlock(bcBlock, parent, block); err != nil {
return errors.Sub(ErrBadBlock, err)
}
+ if err := c.ProcessDPoSConnectBlock(block); err != nil {
+ return err
+ }
+
if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
return err
}
return false, c.connectBlock(bestBlock)
}
- if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 {
+ if bestNode.Height > c.bestNode.Height {
log.Debug("start to reorganize chain")
return false, c.reorganizeChain(bestNode)
}
return false, nil
}
-func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) {
+func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) error {
mapTxFee := c.CalculateBalance(block, true)
- fmt.Println(mapTxFee)
+ if err := c.DoVoting(block, mapTxFee); err != nil {
+ return err
+ }
+ return nil
}
-func DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error {
+func (c *Chain) DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error {
for _, tx := range block.Transactions {
to := tx.Outputs[0]
- var delegate engine.TypedData
+ msg := &dpos.DposMsg{}
- if err := json.Unmarshal(tx.TxData.ReferenceData, delegate); err != nil && to.Amount > 0 {
+ if err := json.Unmarshal(tx.TxData.ReferenceData, &msg); err != nil {
continue
}
var (
}
hash := block.Hash()
height := block.Height
- switch data := delegate.(type) {
- case *engine.DelegateInfoList:
+ switch msg.Type {
+ case vm.OP_DELEGATE:
continue
- case *engine.RegisterForgerData:
+ case vm.OP_REGISTE:
if mapTxFee[tx.Tx.ID] >= consensus.RegisrerForgerFee {
- engine.DposVote.ProcessRegister(address.EncodeAddress(), data.Name, hash, height)
+ data := &dpos.RegisterForgerData{}
+ if err := json.Unmarshal(msg.Data, data); err != nil {
+ return err
+ }
+ c.engine.ProcessRegister(address.EncodeAddress(), data.Name, hash, height)
}
- case *engine.VoteForgerData:
+ case vm.OP_VOTE:
if mapTxFee[tx.Tx.ID] >= consensus.VoteForgerFee {
- engine.DposVote.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height)
+ data := &dpos.VoteForgerData{}
+ if err := json.Unmarshal(msg.Data, data); err != nil {
+ return err
+ }
+ c.engine.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height)
}
- case *engine.CancelVoteForgerData:
+ case vm.OP_REVOKE:
if mapTxFee[tx.Tx.ID] >= consensus.CancelVoteForgerFee {
- engine.DposVote.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height)
+ data := &dpos.CancelVoteForgerData{}
+ if err := json.Unmarshal(msg.Data, data); err != nil {
+ return err
+ }
+ c.engine.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height)
}
}
}
for _, tx := range block.Transactions {
fee := uint64(0)
for _, input := range tx.Inputs {
+
+ if len(tx.TxData.Inputs) == 1 &&
+ (tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType ||
+ tx.TxData.Inputs[0].InputType() == types.ClainPeginInputType) {
+ continue
+ }
+
fee += input.Amount()
value := int64(input.Amount())
address, err = common.NewAddressWitnessPubKeyHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
continue
}
}
- if fIsAdd {
+ if !fIsAdd {
value = 0 - value
}
addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
mapTxFee[tx.Tx.ID] = fee
}
- engine.DposVote.UpdateAddressBalance(addressBalances)
+ c.engine.UpdateAddressBalance(addressBalances)
return mapTxFee
}
+
+func (c *Chain) RepairDPoSData(oldBlockHeight uint64, oldBlockHash bc.Hash) error {
+ block, err := c.GetBlockByHash(&oldBlockHash)
+ if err != nil {
+ return err
+ }
+ if block.Height != oldBlockHeight {
+ return errors.New("The module vote records data with a problem")
+ }
+ for i := block.Height + 1; i < c.bestNode.Height; i++ {
+ b, err := c.GetBlockByHeight(i)
+ if err != nil {
+ return err
+ }
+ if err := c.ProcessDPoSConnectBlock(b); err != nil {
+ return err
+ }
+
+ }
+ return nil
+}
func TestCalcReorganizeNodes(t *testing.T) {
c := &Chain{index: state.NewBlockIndex()}
config.CommonConfig = config.DefaultConfig()
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
header := config.GenesisBlock().BlockHeader
initNode, err := state.NewBlockNode(&header, nil)
}
// NewChain returns a new Chain using store as the underlying storage.
-func NewChain(store Store, txPool *TxPool) (*Chain, error) {
+func NewChain(store Store, txPool *TxPool, engine engine.Engine) (*Chain, error) {
c := &Chain{
orphanManage: NewOrphanManage(),
txPool: txPool,
store: store,
processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
+ engine: engine,
}
c.cond.L = new(sync.Mutex)
Bits uint64
TransactionsMerkleRoot bc.Hash
TransactionStatusHash bc.Hash
- Proof bc.Proof
- Coinbase []byte
- Extra []byte
}
func NewBlockNode(bh *types.BlockHeader, parent *BlockNode) (*BlockNode, error) {
//Bits: bh.Bits,
TransactionsMerkleRoot: bh.TransactionsMerkleRoot,
TransactionStatusHash: bh.TransactionStatusHash,
- Proof: bc.Proof{
- Sign: bh.Proof.Sign,
- ControlProgram: bh.Proof.ControlProgram,
- },
- Coinbase: bh.Coinbase,
- Extra: bh.Extra,
}
/*
if bh.Height == 0 {
Height: node.Height,
PreviousBlockHash: previousBlockHash,
Timestamp: node.Timestamp,
- Proof: types.Proof{
- Sign: node.Proof.Sign,
- ControlProgram: node.Proof.ControlProgram,
- },
BlockCommitment: types.BlockCommitment{
TransactionsMerkleRoot: node.TransactionsMerkleRoot,
TransactionStatusHash: node.TransactionStatusHash,
},
- Coinbase: node.Coinbase,
- Extra: node.Extra,
}
}
log "github.com/sirupsen/logrus"
- "github.com/vapor/chain"
"github.com/vapor/consensus"
- engine "github.com/vapor/consensus/consensus"
"github.com/vapor/errors"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
}
// ValidateBlockHeader check the block's header
-func ValidateBlockHeader(b *bc.Block, block *types.Block, parent *state.BlockNode, c chain.Chain) error {
+func ValidateBlockHeader(b *bc.Block, block *types.Block, parent *state.BlockNode) error {
if b.Version < parent.Version {
return errors.WithDetailf(errVersionRegression, "previous block verson %d, current block version %d", parent.Version, b.Version)
}
return err
}
- if err := engine.GDpos.CheckBlockHeader(block.BlockHeader); err != nil {
- return err
- }
-
- if err := engine.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil {
- return err
- }
-
return nil
}
// ValidateBlock validates a block and the transactions within.
-func ValidateBlock(b *bc.Block, parent *state.BlockNode, block *types.Block, c chain.Chain) error {
+func ValidateBlock(b *bc.Block, parent *state.BlockNode, block *types.Block) error {
startTime := time.Now()
- if err := ValidateBlockHeader(b, block, parent, c); err != nil {
- return err
- }
-
- if err := engine.GDpos.CheckBlock(*block, true); err != nil {
+ if err := ValidateBlockHeader(b, block, parent); err != nil {
return err
}
OP_ENTRYID Op = 0xca
OP_OUTPUTID Op = 0xcb
OP_BLOCKHEIGHT Op = 0xcd
+
+ OP_DELEGATE Op = 0xd0
+ OP_REGISTE Op = 0xd1
+ OP_VOTE Op = 0xd2
+ OP_REVOKE Op = 0xd3
)
type opInfo struct {
"github.com/vapor/blockchain/pseudohsm"
"github.com/vapor/blockchain/signers"
"github.com/vapor/blockchain/txbuilder"
+ "github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
+ "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/database/storage"
if err := SetUtxoView(testDB, utxoView); err != nil {
return nil, nil, nil, err
}
+ var engine engine.Engine
+ switch config.CommonConfig.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
store := leveldb.NewStore(testDB)
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ chain, err := protocol.NewChain(store, txPool, engine)
if err != nil {
return nil, nil, nil, err
}
}
}
- block, err := mining.NewBlockTemplate(chain, txPool, nil, nil)
+ block, err := mining.NewBlockTemplate(chain, txPool, nil, nil, nil)
if err != nil {
return err
}
package test
import (
- "github.com/vapor/consensus"
- "github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519/chainkd"
- "github.com/vapor/errors"
"github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
"github.com/vapor/protocol/validation"
"github.com/vapor/protocol/vm"
- "github.com/vapor/protocol/vm/vmutil"
)
// NewBlock create block according to the current status of chain
}
b.TransactionStatusHash, err = types.TxStatusMerkleRoot(txStatus.VerifyStatus)
- proof, err := generateProof(*b)
- if err != nil {
- return nil, err
- }
- b.Proof = proof
return b, err
}
-func generateProof(block types.Block) (types.Proof, error) {
- var xPrv chainkd.XPrv
- if consensus.ActiveNetParams.Signer == "" {
- return types.Proof{}, errors.New("Signer is empty")
- }
- xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
- sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
- pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
- control, err := vmutil.P2WPKHProgram([]byte(pubHash))
- if err != nil {
- return types.Proof{}, err
- }
- return types.Proof{Sign: sign, ControlProgram: control}, nil
-}
-
// ReplaceCoinbase replace the coinbase tx of block with coinbaseTx
func ReplaceCoinbase(block *types.Block, coinbaseTx *types.Tx) (err error) {
block.Transactions[0] = coinbaseTx
"github.com/vapor/common"
"github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
+ "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/protocol"
func MockChain(testDB dbm.DB) (*protocol.Chain, *leveldb.Store, *protocol.TxPool, error) {
config.CommonConfig = config.DefaultConfig()
consensus.SoloNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
return nil, nil, nil, err
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
store := leveldb.NewStore(testDB)
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ var engine engine.Engine
+ switch config.CommonConfig.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
+
+ chain, err := protocol.NewChain(store, txPool, engine)
consensus.ActiveNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
return chain, store, txPool, err
}
if err != nil {
return err
}
- config.CommonConfig.Consensus.Dpos.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
- address, err := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.SoloNetParams)
+ config.CommonConfig.Consensus.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
+ address, err := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.SoloNetParams)
if err != nil {
return err
}
// with code 1.
func TrapSignal(cb func()) {
c := make(chan os.Signal, 1)
- signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+ signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
go func() {
for sig := range c {
fmt.Printf("captured %v, exiting...\n", sig)
func TestWalletUnconfirmedTxs(t *testing.T) {
config.CommonConfig = config.DefaultConfig()
consensus.SoloNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
- config.CommonConfig.Consensus.Dpos.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
- address, err := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.SoloNetParams)
+ config.CommonConfig.Consensus.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
+ address, err := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
"time"
dbm "github.com/tendermint/tmlibs/db"
- "github.com/vapor/blockchain/signers"
- "github.com/vapor/common"
- "github.com/vapor/config"
-
"github.com/vapor/account"
"github.com/vapor/asset"
"github.com/vapor/blockchain/pseudohsm"
+ "github.com/vapor/blockchain/signers"
"github.com/vapor/blockchain/txbuilder"
+ "github.com/vapor/common"
+ "github.com/vapor/config"
"github.com/vapor/consensus"
+ engine "github.com/vapor/consensus/consensus"
+ "github.com/vapor/consensus/consensus/dpos"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/database/leveldb"
"github.com/vapor/protocol"
func TestWalletUpdate(t *testing.T) {
config.CommonConfig = config.DefaultConfig()
consensus.SoloNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- config.CommonConfig.Consensus.Dpos.SelfVoteSigners = append(config.CommonConfig.Consensus.Dpos.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
- config.CommonConfig.Consensus.Dpos.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
- for _, v := range config.CommonConfig.Consensus.Dpos.SelfVoteSigners {
+ config.CommonConfig.Consensus.SelfVoteSigners = append(config.CommonConfig.Consensus.SelfVoteSigners, "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep")
+ config.CommonConfig.Consensus.XPrv = "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445"
+ for _, v := range config.CommonConfig.Consensus.SelfVoteSigners {
address, err := common.DecodeAddress(v, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
- config.CommonConfig.Consensus.Dpos.Signers = append(config.CommonConfig.Consensus.Dpos.Signers, address)
+ config.CommonConfig.Consensus.Signers = append(config.CommonConfig.Consensus.Signers, address)
}
- config.CommonConfig.Consensus.Dpos.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
- address, err := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.SoloNetParams)
+ config.CommonConfig.Consensus.Coinbase = "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
+ address, err := common.DecodeAddress(config.CommonConfig.Consensus.Coinbase, &consensus.SoloNetParams)
if err != nil {
t.Fatal(err)
}
store := leveldb.NewStore(testDB)
txPool := protocol.NewTxPool(store)
- chain, err := protocol.NewChain(store, txPool)
+ var engine engine.Engine
+ switch config.CommonConfig.Consensus.Type {
+ case "dpos":
+ engine = dpos.GDpos
+ }
+ chain, err := protocol.NewChain(store, txPool, engine)
if err != nil {
t.Fatal(err)
}