From: mars Date: Wed, 20 Mar 2019 09:10:21 +0000 (+0800) Subject: Add the implementation for dppos X-Git-Tag: v1.0.5~219^2 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=e57f41f037f3f37fd7253e34f8a04e60a125e634 Add the implementation for dppos --- diff --git a/account/accounts_test.go b/account/accounts_test.go index f94c51ca..b1710df1 100644 --- a/account/accounts_test.go +++ b/account/accounts_test.go @@ -14,6 +14,8 @@ import ( "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" @@ -211,14 +213,14 @@ func mockAccountManager(t *testing.T) *Manager { 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 { @@ -231,7 +233,12 @@ func mockAccountManager(t *testing.T) *Manager { 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) } diff --git a/account/dpos_builder.go b/account/dpos_builder.go index 572183e5..64f50613 100644 --- a/account/dpos_builder.go +++ b/account/dpos_builder.go @@ -3,16 +3,19 @@ package account 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" ) @@ -25,12 +28,11 @@ func (m *Manager) DecodeDposAction(data []byte) (txbuilder.Action, error) { 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 { @@ -39,40 +41,94 @@ func (a *DopsAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) er 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") } @@ -90,7 +146,7 @@ func (a *DopsAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) er } } 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 } @@ -117,7 +173,7 @@ func DposTx(from, to string, stake uint64, u *UTXO, txType types.TxType, h uint6 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 == "" { @@ -157,7 +213,7 @@ func spendInput(u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) 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 == "" { diff --git a/api/api.go b/api/api.go index af242a6c..1e0d303d 100644 --- a/api/api.go +++ b/api/api.go @@ -253,16 +253,17 @@ func (a *API) buildHandler() { 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") } diff --git a/api/api_test.go b/api/api_test.go index c33e0532..bc7627c9 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -102,7 +102,7 @@ func TestAPIHandler(t *testing.T) { } 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 { @@ -133,7 +133,7 @@ func TestEstimateTxGasRange(t *testing.T) { }{ { 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, }, diff --git a/api/dpos.go b/api/dpos.go new file mode 100644 index 00000000..7ea75c00 --- /dev/null +++ b/api/dpos.go @@ -0,0 +1,40 @@ +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)) +} diff --git a/api/dpos_vote.go b/api/dpos_vote.go deleted file mode 100644 index a7333eef..00000000 --- a/api/dpos_vote.go +++ /dev/null @@ -1,72 +0,0 @@ -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}) -} diff --git a/api/hsm.go b/api/hsm.go index 96b968e5..100db72a 100644 --- a/api/hsm.go +++ b/api/hsm.go @@ -5,6 +5,7 @@ import ( log "github.com/sirupsen/logrus" + "github.com/vapor/blockchain/pseudohsm" "github.com/vapor/blockchain/txbuilder" "github.com/vapor/common" "github.com/vapor/consensus" @@ -83,6 +84,21 @@ func (a *API) signTemplate(ctx context.Context, x struct { 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"` diff --git a/api/transact.go b/api/transact.go index a4acb346..2b11215e 100644 --- a/api/transact.go +++ b/api/transact.go @@ -34,7 +34,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro "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] @@ -49,7 +49,7 @@ func onlyHaveInputActions(req *BuildRequest) (bool, error) { 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" { diff --git a/asset/asset_test.go b/asset/asset_test.go index f0127eea..fe85e21b 100644 --- a/asset/asset_test.go +++ b/asset/asset_test.go @@ -14,6 +14,8 @@ import ( "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" @@ -153,9 +155,14 @@ func TestListAssets(t *testing.T) { } 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 } @@ -165,14 +172,14 @@ func mockChain(testDB dbm.DB) (*protocol.Chain, error) { 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 { diff --git a/blockchain/txbuilder/builder.go b/blockchain/txbuilder/builder.go index b93b6dbe..a9f5e064 100644 --- a/blockchain/txbuilder/builder.go +++ b/blockchain/txbuilder/builder.go @@ -24,6 +24,7 @@ type TemplateBuilder struct { timeRange uint64 rollbacks []func() callbacks []func() error + referenceData []byte } // AddInput add inputs of transactions @@ -45,6 +46,10 @@ func (b *TemplateBuilder) AddOutput(o *types.TxOutput) error { 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) @@ -131,6 +136,8 @@ func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) { tx.Inputs = append(tx.Inputs, in) } + tx.ReferenceData = b.referenceData + tpl.Transaction = types.NewTx(*tx) tpl.Fee = CalculateTxFee(tpl.Transaction) return tpl, tx, nil diff --git a/cmd/vapor/consensus.json b/cmd/vapor/consensus.json index ee174372..7ed772f4 100644 --- a/cmd/vapor/consensus.json +++ b/cmd/vapor/consensus.json @@ -1,16 +1,14 @@ { "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 diff --git a/cmd/vapor/side_chain/config.toml b/cmd/vapor/side_chain/config.toml index 56122e22..4ec6cb7f 100644 --- a/cmd/vapor/side_chain/config.toml +++ b/cmd/vapor/side_chain/config.toml @@ -6,4 +6,4 @@ api_addr = "0.0.0.0:8888" chain_id = "solonet" [p2p] laddr = "tcp://0.0.0.0:56658" -seeds = "" +seeds = "127.0.0.1:56659" diff --git a/config/config.go b/config/config.go index 7e382170..be5dce68 100644 --- a/config/config.go +++ b/config/config.go @@ -178,12 +178,19 @@ type WebsocketConfig struct { } 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 @@ -241,7 +248,6 @@ func DefaultWebsocketConfig() *WebsocketConfig { func DefaultDposConfig() *DposConfig { return &DposConfig{ Period: 1, - Epoch: 300, MaxSignerCount: 1, MinVoterBalance: 0, GenesisTimestamp: 1524549600, @@ -249,7 +255,12 @@ func DefaultDposConfig() *DposConfig { } func DefaultConsensusCOnfig() *ConsensusConfig { - return &ConsensusConfig{Dpos: DefaultDposConfig()} + return &ConsensusConfig{ + Type: "dpos", + Period: 1, + MaxSignerCount: 1, + MinVoterBalance: 0, + GenesisTimestamp: 1524549600} } //----------------------------------------------------------------------------- diff --git a/config/genesis.go b/config/genesis.go index 1443862f..3a10ded0 100644 --- a/config/genesis.go +++ b/config/genesis.go @@ -9,7 +9,6 @@ import ( "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" @@ -23,7 +22,7 @@ func commitToArguments() (res *[32]byte) { 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) } @@ -76,13 +75,6 @@ func mainNetGenesisBlock() *types.Block { 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, @@ -92,7 +84,6 @@ func mainNetGenesisBlock() *types.Block { TransactionsMerkleRoot: merkleRoot, TransactionStatusHash: txStatusHash, }, - Coinbase: b, }, Transactions: []*types.Tx{tx}, } @@ -114,14 +105,6 @@ func testNetGenesisBlock() *types.Block { 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, @@ -131,7 +114,6 @@ func testNetGenesisBlock() *types.Block { TransactionsMerkleRoot: merkleRoot, TransactionStatusHash: txStatusHash, }, - Coinbase: b, }, Transactions: []*types.Tx{tx}, } @@ -154,23 +136,15 @@ func soloNetGenesisBlock() *types.Block { 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}, } diff --git a/consensus/consensus/consensus.go b/consensus/consensus/consensus.go index 61c2dfcd..9c506582 100644 --- a/consensus/consensus/consensus.go +++ b/consensus/consensus/consensus.go @@ -2,28 +2,32 @@ package consensus 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 } diff --git a/consensus/consensus/dpos.go b/consensus/consensus/dpos.go deleted file mode 100644 index 0036e8dc..00000000 --- a/consensus/consensus/dpos.go +++ /dev/null @@ -1,312 +0,0 @@ -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 -} diff --git a/consensus/consensus/dpos/custom_tx.go b/consensus/consensus/dpos/custom_tx.go deleted file mode 100644 index 586abeab..00000000 --- a/consensus/consensus/dpos/custom_tx.go +++ /dev/null @@ -1,322 +0,0 @@ -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 -} diff --git a/consensus/consensus/dpos/dpos.go b/consensus/consensus/dpos/dpos.go index 5eaf632b..de0ed2e8 100644 --- a/consensus/consensus/dpos/dpos.go +++ b/consensus/consensus/dpos/dpos.go @@ -1,627 +1,637 @@ 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 } diff --git a/consensus/consensus/dpos/signer_queue.go b/consensus/consensus/dpos/signer_queue.go deleted file mode 100644 index 0b070015..00000000 --- a/consensus/consensus/dpos/signer_queue.go +++ /dev/null @@ -1,153 +0,0 @@ -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 - -} diff --git a/consensus/consensus/dpos/snapshot.go b/consensus/consensus/dpos/snapshot.go deleted file mode 100644 index 43a6a7aa..00000000 --- a/consensus/consensus/dpos/snapshot.go +++ /dev/null @@ -1,549 +0,0 @@ -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)) -} diff --git a/consensus/consensus/vote.go b/consensus/consensus/dpos/vote.go similarity index 51% rename from consensus/consensus/vote.go rename to consensus/consensus/dpos/vote.go index 65ce0019..7daa793e 100644 --- a/consensus/consensus/vote.go +++ b/consensus/consensus/dpos/vote.go @@ -1,14 +1,20 @@ -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" ) @@ -23,11 +29,6 @@ const ( 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 @@ -54,11 +55,37 @@ type Vote struct { 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) @@ -66,12 +93,8 @@ func (v *Vote) new(blockHeight uint64, blockHash bc.Hash) error { 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 { @@ -84,16 +107,15 @@ func (v *Vote) new(blockHeight uint64, blockHash bc.Hash) error { 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 @@ -124,14 +146,23 @@ func (v *Vote) ProcessVote(voterAddress string, delegates []string, hash bc.Hash 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 } @@ -169,12 +200,6 @@ func (v *Vote) ProcessCancelVote(voterAddress string, delegates []string, hash b 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 @@ -197,6 +222,7 @@ func (v *Vote) Store(blockHeight uint64, blockHash bc.Hash) error { } if err := v.WriteControlFile(blockHeight, blockHash, v.controlFileName+"-temp"); err != nil { + v.Delete(blockHash) return err } @@ -206,13 +232,13 @@ func (v *Vote) Store(blockHeight uint64, blockHash bc.Hash) error { ) 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 } @@ -237,7 +263,6 @@ func (v *Vote) Write(blockHash bc.Hash) error { 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 @@ -263,17 +288,11 @@ func (v *Vote) read() error { 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 { @@ -292,33 +311,115 @@ func (v *Vote) read() error { } 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 { @@ -356,6 +457,151 @@ func (v *Vote) WriteControlFile(blockHeight uint64, blockHash bc.Hash, fileName 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 } diff --git a/consensus/consensus/vote_type.go b/consensus/consensus/dpos/vote_type.go similarity index 71% rename from consensus/consensus/vote_type.go rename to consensus/consensus/dpos/vote_type.go index d25a0aaa..1dec1fbd 100644 --- a/consensus/consensus/vote_type.go +++ b/consensus/consensus/dpos/vote_type.go @@ -1,8 +1,9 @@ -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. @@ -17,11 +18,16 @@ type TypedData interface { 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 } @@ -33,13 +39,13 @@ type RegisterForgerData struct { 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 } diff --git a/consensus/consensus/errors.go b/consensus/consensus/errors.go deleted file mode 100644 index b9cb3590..00000000 --- a/consensus/consensus/errors.go +++ /dev/null @@ -1,21 +0,0 @@ -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") -) diff --git a/consensus/general.go b/consensus/general.go index 8db576d1..81af2f15 100644 --- a/consensus/general.go +++ b/consensus/general.go @@ -72,7 +72,7 @@ const ( 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 } diff --git a/database/leveldb/store_test.go b/database/leveldb/store_test.go index ddad037a..a126447a 100644 --- a/database/leveldb/store_test.go +++ b/database/leveldb/store_test.go @@ -18,14 +18,14 @@ func TestLoadBlockIndex(t *testing.T) { 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() @@ -82,14 +82,14 @@ func TestLoadBlockIndexBestHeight(t *testing.T) { 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 { diff --git a/mining/miner/miner.go b/mining/miner/miner.go index 9b3f29da..378a78e5 100644 --- a/mining/miner/miner.go +++ b/mining/miner/miner.go @@ -1,13 +1,9 @@ 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" @@ -16,14 +12,9 @@ import ( "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 ( @@ -33,8 +24,6 @@ const ( module = "miner" ) -var ConsensusEngine engine.Engine - // Miner creates blocks and searches for proof-of-work values. type Miner struct { sync.Mutex @@ -52,14 +41,6 @@ type Miner struct { } 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, @@ -67,27 +48,10 @@ func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protoc 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 @@ -104,9 +68,12 @@ out: 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 } @@ -121,12 +88,7 @@ out: 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, @@ -139,50 +101,12 @@ out: } 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. diff --git a/mining/mining.go b/mining/mining.go index dc47aaa6..97590f5d 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -7,6 +7,8 @@ import ( "strconv" "time" + "github.com/vapor/protocol/vm" + "github.com/vapor/common" log "github.com/sirupsen/logrus" @@ -16,6 +18,7 @@ import ( "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" @@ -29,12 +32,12 @@ import ( // 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) @@ -64,19 +67,21 @@ func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeigh 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) @@ -84,6 +89,15 @@ func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeigh 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{ @@ -94,7 +108,7 @@ func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeigh } // 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 { @@ -109,25 +123,12 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager 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{} @@ -175,13 +176,9 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager } } - 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") } diff --git a/node/node.go b/node/node.go index 8021a660..61176c22 100644 --- a/node/node.go +++ b/node/node.go @@ -28,7 +28,7 @@ import ( 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" @@ -46,8 +46,6 @@ const ( maxNewBlockChSize = 1024 ) -var consensusEngine engine.Engine - type Node struct { cmn.BaseService @@ -69,6 +67,8 @@ type Node struct { miningEnable bool newBlockCh chan *bc.Hash + + engine engine.Engine } func NewNode(config *cfg.Config) *Node { @@ -93,8 +93,14 @@ 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)) } @@ -118,7 +124,7 @@ func NewNode(config *cfg.Config) *Node { } 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)) } @@ -156,6 +162,11 @@ func NewNode(config *cfg.Config) *Node { }() } + switch config.Consensus.Type { + case "dpos": + initDpos(chain, config) + } + node := &Node{ config: config, syncManager: syncManager, @@ -167,12 +178,10 @@ func NewNode(config *cfg.Config) *Node { 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 @@ -297,6 +306,10 @@ func (n *Node) OnStart() error { } 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() @@ -362,24 +375,31 @@ func initConsensusConfig(config *cfg.Config) { 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)) + } + } } diff --git a/protocol/bc/bc.pb.go b/protocol/bc/bc.pb.go index b3466143..984df23b 100644 --- a/protocol/bc/bc.pb.go +++ b/protocol/bc/bc.pb.go @@ -390,9 +390,6 @@ type BlockHeader struct { 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{} } @@ -463,33 +460,13 @@ func (m *BlockHeader) GetTransactionStatus() *TransactionStatus { 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{} } @@ -532,6 +509,13 @@ func (m *TxHeader) GetResultIds() []*Hash { 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"` } @@ -943,74 +927,72 @@ func init() { 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, } diff --git a/protocol/bc/bc.proto b/protocol/bc/bc.proto index e45143a4..0ee23f8d 100644 --- a/protocol/bc/bc.proto +++ b/protocol/bc/bc.proto @@ -76,9 +76,6 @@ message BlockHeader { uint64 nonce = 7; uint64 bits = 8; TransactionStatus transaction_status = 9; - Proof Proof = 10; - bytes extra = 11; - bytes coinbase = 12; } message TxHeader { @@ -87,6 +84,7 @@ message TxHeader { Hash data = 3; uint64 time_range = 4; repeated Hash result_ids = 5; + bool side = 6; } message TxVerifyResult { diff --git a/protocol/bc/blockheader.go b/protocol/bc/blockheader.go index 45177554..2d912bd0 100644 --- a/protocol/bc/blockheader.go +++ b/protocol/bc/blockheader.go @@ -11,17 +11,13 @@ func (bh *BlockHeader) writeForHash(w io.Writer) { 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, @@ -30,8 +26,5 @@ func NewBlockHeader(version, height uint64, previousBlockID *Hash, timestamp uin TransactionsRoot: transactionsRoot, TransactionStatusHash: transactionStatusHash, TransactionStatus: nil, - Proof: proof, - Extra: extra, - Coinbase: coinbase, } } diff --git a/protocol/bc/entry_test.go b/protocol/bc/entry_test.go index 1ab9151e..ab9e810e 100644 --- a/protocol/bc/entry_test.go +++ b/protocol/bc/entry_test.go @@ -11,7 +11,7 @@ func BenchmarkEntryID(b *testing.B) { 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), diff --git a/protocol/bc/txheader.go b/protocol/bc/txheader.go index 048ef73b..888ce31f 100644 --- a/protocol/bc/txheader.go +++ b/protocol/bc/txheader.go @@ -12,16 +12,19 @@ func (h *TxHeader) writeForHash(w io.Writer) { 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, } } diff --git a/protocol/bc/types/block_header.go b/protocol/bc/types/block_header.go index ab47019a..ab531578 100644 --- a/protocol/bc/types/block_header.go +++ b/protocol/bc/types/block_header.go @@ -12,48 +12,12 @@ import ( "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 } @@ -117,18 +81,9 @@ func (bh *BlockHeader) readFrom(r *blockchain.Reader) (serflag uint8, err error) 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 } @@ -155,17 +110,8 @@ func (bh *BlockHeader) writeTo(w io.Writer, serflags uint8) (err error) { 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 } diff --git a/protocol/bc/types/bytom/types/map.go b/protocol/bc/types/bytom/types/map.go index 09e1fa4a..4892c195 100644 --- a/protocol/bc/types/bytom/types/map.go +++ b/protocol/bc/types/bytom/types/map.go @@ -170,7 +170,7 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash 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 } diff --git a/protocol/bc/types/dpos.go b/protocol/bc/types/dpos.go index 276d9e55..73a600df 100644 --- a/protocol/bc/types/dpos.go +++ b/protocol/bc/types/dpos.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - "github.com/vapor/protocol/bc" ) @@ -20,15 +18,7 @@ type DposTx struct { 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, diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index 8dd10a49..9ad4037b 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -229,13 +229,12 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash 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 } diff --git a/protocol/bc/types/merkle_test.go b/protocol/bc/types/merkle_test.go index 05d8c0cc..2f22c558 100644 --- a/protocol/bc/types/merkle_test.go +++ b/protocol/bc/types/merkle_test.go @@ -23,7 +23,7 @@ func TestMerkleRoot(t *testing.T) { []byte("00000"), }, }, - want: testutil.MustDecodeHash("fe34dbd5da0ce3656f423fd7aad7fc7e879353174d33a6446c2ed0e3f3512101"), + want: testutil.MustDecodeHash("011a6b552cc8eced01c403b138c51f906d0ccd0bbdf986d2b3e0cc69a4291737"), }, { witnesses: [][][]byte{ { @@ -35,7 +35,7 @@ func TestMerkleRoot(t *testing.T) { []byte("111111"), }, }, - want: testutil.MustDecodeHash("0e4b4c1af18b8f59997804d69f8f66879ad5e30027346ee003ff7c7a512e5554"), + want: testutil.MustDecodeHash("64cef8abecac041b87110309dd9068d4935a31fb1bd1572144d11ead9da91dba"), }, { witnesses: [][][]byte{ { @@ -48,7 +48,7 @@ func TestMerkleRoot(t *testing.T) { []byte("222222"), }, }, - want: testutil.MustDecodeHash("0e4b4c1af18b8f59997804d69f8f66879ad5e30027346ee003ff7c7a512e5554"), + want: testutil.MustDecodeHash("64cef8abecac041b87110309dd9068d4935a31fb1bd1572144d11ead9da91dba"), }} for _, c := range cases { diff --git a/protocol/bc/types/spend.go b/protocol/bc/types/spend.go index 01d60c3c..5342cdeb 100644 --- a/protocol/bc/types/spend.go +++ b/protocol/bc/types/spend.go @@ -8,11 +8,9 @@ type TxType uint8 const ( Binary TxType = iota - LoginCandidate - LogoutCandidate - Delegate - UnDelegate - ConfirmTx + Registe + Vote + CancelVote ) // SpendInput satisfies the TypedInput interface and represents a spend transaction. diff --git a/protocol/bc/types/transaction.go b/protocol/bc/types/transaction.go index c98e673e..b8b83c26 100644 --- a/protocol/bc/types/transaction.go +++ b/protocol/bc/types/transaction.go @@ -139,6 +139,11 @@ func (tx *TxData) readFrom(r *blockchain.Reader) (err error) { 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 } @@ -181,5 +186,10 @@ func (tx *TxData) writeTo(w io.Writer, serflags byte) error { 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 } diff --git a/protocol/block.go b/protocol/block.go index 1771a990..f91c33d9 100644 --- a/protocol/block.go +++ b/protocol/block.go @@ -2,13 +2,15 @@ package protocol 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" @@ -159,15 +161,38 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { 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 } @@ -259,24 +284,27 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) { 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 ( @@ -292,20 +320,32 @@ func DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error { } 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) } } } @@ -324,6 +364,13 @@ func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]ui 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) @@ -348,7 +395,7 @@ func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]ui continue } } - if fIsAdd { + if !fIsAdd { value = 0 - value } addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value}) @@ -356,6 +403,27 @@ func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]ui 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 +} diff --git a/protocol/block_test.go b/protocol/block_test.go index f60d4399..51534373 100644 --- a/protocol/block_test.go +++ b/protocol/block_test.go @@ -13,14 +13,14 @@ import ( 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) diff --git a/protocol/protocol.go b/protocol/protocol.go index 7bd85188..ba60e08d 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -29,12 +29,13 @@ type Chain struct { } // 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) diff --git a/protocol/state/blockindex.go b/protocol/state/blockindex.go index 0a610f27..4a3ed2a2 100644 --- a/protocol/state/blockindex.go +++ b/protocol/state/blockindex.go @@ -32,9 +32,6 @@ type BlockNode struct { Bits uint64 TransactionsMerkleRoot bc.Hash TransactionStatusHash bc.Hash - Proof bc.Proof - Coinbase []byte - Extra []byte } func NewBlockNode(bh *types.BlockHeader, parent *BlockNode) (*BlockNode, error) { @@ -53,12 +50,6 @@ 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 { @@ -82,16 +73,10 @@ func (node *BlockNode) BlockHeader() *types.BlockHeader { 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, } } diff --git a/protocol/validation/block.go b/protocol/validation/block.go index aa18b552..17aff8ae 100644 --- a/protocol/validation/block.go +++ b/protocol/validation/block.go @@ -5,9 +5,7 @@ import ( 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" @@ -56,7 +54,7 @@ func checkCoinbaseAmount(b *bc.Block, amount uint64) error { } // 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) } @@ -70,25 +68,13 @@ func ValidateBlockHeader(b *bc.Block, block *types.Block, parent *state.BlockNod 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 } diff --git a/protocol/vm/ops.go b/protocol/vm/ops.go index 5052c62d..20387486 100644 --- a/protocol/vm/ops.go +++ b/protocol/vm/ops.go @@ -210,6 +210,11 @@ const ( 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 { diff --git a/test/bench_blockchain_test.go b/test/bench_blockchain_test.go index abdb2e07..8ccb36b7 100644 --- a/test/bench_blockchain_test.go +++ b/test/bench_blockchain_test.go @@ -13,7 +13,10 @@ import ( "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" @@ -136,10 +139,15 @@ func GenerateChainData(dirPath string, testDB dbm.DB, txNumber, otherAssetNum in 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 } @@ -156,7 +164,7 @@ func InsertChain(chain *protocol.Chain, txPool *protocol.TxPool, txs []*types.Tx } } - block, err := mining.NewBlockTemplate(chain, txPool, nil, nil) + block, err := mining.NewBlockTemplate(chain, txPool, nil, nil, nil) if err != nil { return err } diff --git a/test/block_test_util.go b/test/block_test_util.go index e609d855..6915653b 100644 --- a/test/block_test_util.go +++ b/test/block_test_util.go @@ -1,16 +1,11 @@ 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 @@ -67,29 +62,9 @@ func NewBlock(chain *protocol.Chain, txs []*types.Tx, controlProgram []byte) (*t } 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 diff --git a/test/util.go b/test/util.go index 3377f126..1cfa781a 100644 --- a/test/util.go +++ b/test/util.go @@ -12,6 +12,8 @@ import ( "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" @@ -29,19 +31,25 @@ const ( 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 } diff --git a/test/wallet_test_util.go b/test/wallet_test_util.go index 261c087a..1ef1dc2d 100644 --- a/test/wallet_test_util.go +++ b/test/wallet_test_util.go @@ -259,8 +259,8 @@ func (cfg *walletTestConfig) Run() error { 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 } diff --git a/vendor/github.com/tendermint/tmlibs/common/os.go b/vendor/github.com/tendermint/tmlibs/common/os.go index 36fc969f..4a9f3406 100644 --- a/vendor/github.com/tendermint/tmlibs/common/os.go +++ b/vendor/github.com/tendermint/tmlibs/common/os.go @@ -39,7 +39,7 @@ func GoPath() string { // 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) diff --git a/wallet/unconfirmed_test.go b/wallet/unconfirmed_test.go index 047e4120..310b4058 100644 --- a/wallet/unconfirmed_test.go +++ b/wallet/unconfirmed_test.go @@ -23,17 +23,17 @@ import ( 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) } diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index 519a6b7a..c9f8b4a1 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -7,15 +7,16 @@ import ( "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" @@ -26,17 +27,17 @@ import ( 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) } @@ -53,7 +54,12 @@ func TestWalletUpdate(t *testing.T) { 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) }