Commit 2aa47b88 authored by madengji's avatar madengji Committed by 33cn

bls sign commit part

parent 9bc6a7df
......@@ -91,6 +91,7 @@ type subConfig struct {
MultiDownServerRspTime uint32 `json:"multiDownServerRspTime,omitempty"`
RmCommitParamMainHeight int64 `json:"rmCommitParamMainHeight,omitempty"`
JumpDownloadClose bool `json:"jumpDownloadClose,omitempty"`
BlsSignOff bool `json:"blsSignOff,omitempty"`
}
// New function to init paracross env
......
......@@ -19,11 +19,14 @@ import (
"bytes"
"math/big"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/types"
paracross "github.com/33cn/plugin/plugin/dapp/paracross/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/phoreproject/bls/g2pubs"
"github.com/pkg/errors"
)
......@@ -60,6 +63,8 @@ type commitMsgClient struct {
txFeeRate int64
selfConsEnableList []*paraSelfConsEnable //适配在自共识合约配置前有自共识的平行链项目,fork之后,采用合约配置
privateKey crypto.PrivKey
blsPriKey *g2pubs.SecretKey
blsPubKey *g2pubs.PublicKey
quit chan struct{}
mutex sync.Mutex
}
......@@ -360,7 +365,19 @@ func (client *commitMsgClient) getSendingTx(startHeight, endHeight int64) (*type
return nil, 0
}
signTx, count, err := client.calcCommitMsgTxs(status, atomic.LoadInt64(&client.txFeeRate))
var commits []*pt.ParacrossCommitAction
for _, stat := range status {
commits = append(commits, &pt.ParacrossCommitAction{Status: stat})
}
if !client.paraClient.subCfg.BlsSignOff {
err = client.blsSign(commits)
if err != nil {
return nil, 0
}
}
signTx, count, err := client.calcCommitMsgTxs(commits, atomic.LoadInt64(&client.txFeeRate))
if err != nil || signTx == nil {
return nil, 0
}
......@@ -376,12 +393,12 @@ func (client *commitMsgClient) getSendingTx(startHeight, endHeight int64) (*type
return signTx, count
}
func (client *commitMsgClient) calcCommitMsgTxs(notifications []*pt.ParacrossNodeStatus, feeRate int64) (*types.Transaction, int64, error) {
func (client *commitMsgClient) calcCommitMsgTxs(notifications []*pt.ParacrossCommitAction, feeRate int64) (*types.Transaction, int64, error) {
txs, count, err := client.batchCalcTxGroup(notifications, feeRate)
if err != nil {
txs, err = client.singleCalcTx((notifications)[0], feeRate)
if err != nil {
plog.Error("single calc tx", "height", notifications[0].Height)
plog.Error("single calc tx", "height", notifications[0].Status.Height)
return nil, 0, err
}
......@@ -429,14 +446,14 @@ func (client *commitMsgClient) getExecName(commitHeight int64) string {
}
func (client *commitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossNodeStatus, feeRate int64) (*types.Transaction, int, error) {
func (client *commitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossCommitAction, feeRate int64) (*types.Transaction, int, error) {
var rawTxs types.Transactions
cfg := client.paraClient.GetAPI().GetConfig()
for _, status := range notifications {
execName := client.getExecName(status.Height)
tx, err := paracross.CreateRawCommitTx4MainChain(cfg, status, execName, feeRate)
for _, notify := range notifications {
execName := client.getExecName(notify.Status.Height)
tx, err := paracross.CreateRawCommitTx4MainChain(cfg, notify, execName, feeRate)
if err != nil {
plog.Error("para get commit tx", "block height", status.Height)
plog.Error("para get commit tx", "block height", notify.Status.Height)
return nil, 0, err
}
rawTxs.Txs = append(rawTxs.Txs, tx)
......@@ -449,12 +466,12 @@ func (client *commitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossNod
return txs, len(notifications), nil
}
func (client *commitMsgClient) singleCalcTx(status *pt.ParacrossNodeStatus, feeRate int64) (*types.Transaction, error) {
func (client *commitMsgClient) singleCalcTx(notify *pt.ParacrossCommitAction, feeRate int64) (*types.Transaction, error) {
cfg := client.paraClient.GetAPI().GetConfig()
execName := client.getExecName(status.Height)
tx, err := paracross.CreateRawCommitTx4MainChain(cfg, status, execName, feeRate)
execName := client.getExecName(notify.Status.Height)
tx, err := paracross.CreateRawCommitTx4MainChain(cfg, notify, execName, feeRate)
if err != nil {
plog.Error("para get commit tx", "block height", status.Height)
plog.Error("para get commit tx", "block height", notify.Status.Height)
return nil, err
}
tx.Sign(types.SECP256K1, client.privateKey)
......@@ -902,6 +919,10 @@ func (client *commitMsgClient) fetchPriKey() error {
}
client.privateKey = priKey
client.blsPriKey = getBlsPriKey(priKey.Bytes())
client.blsPubKey = g2pubs.PrivToPub(client.blsPriKey)
serial := client.blsPubKey.Serialize()
plog.Info("para commit get pub bls", "final keys", common.ToHex(serial[:]))
plog.Info("para commit fetchPriKey success")
return nil
}
......@@ -958,3 +979,62 @@ func (client *commitMsgClient) isSelfConsEnable(height int64) bool {
}
return false
}
//to repeat get prikey's hash until in range of bls's private key
func getBlsPriKey(key []byte) *g2pubs.SecretKey {
var newKey [common.Sha256Len]byte
copy(newKey[:], key[:])
for {
plog.Info("para commit getBlsPriKey", "keys", common.ToHex(newKey[:]))
secret := g2pubs.DeserializeSecretKey(newKey)
if nil != secret.GetFRElement() {
serial := secret.Serialize()
plog.Info("para commit getBlsPriKey", "final keys", common.ToHex(serial[:]), "string", secret.String())
return secret
}
copy(newKey[:], common.Sha256(newKey[:]))
}
}
func (client *commitMsgClient) blsSign(commits []*pt.ParacrossCommitAction) error {
nodeStr, err := client.getNodeGroupAddrs()
if err != nil || len(nodeStr) <= 0 {
plog.Info("bls sign", "nodestr", nodeStr, "err", err)
return types.ErrInvalidParam
}
nodes := strings.Split(nodeStr, ",")
bitMap, remains := setAddrsBitMap(nodes, []string{client.authAccount})
if len(remains) > 0 {
plog.Error("bls sign addrs remains", "remains", remains, "nodestr", nodeStr, "bitmap", bitMap, "nodes", nodes)
}
if remains[client.authAccount] {
plog.Error("bls sign addrs miss setmap", "auth", client.authAccount, "remains", remains)
return types.ErrInvalidParam
}
for _, cmt := range commits {
data := types.Encode(cmt.Status)
plog.Debug("blsign msg", "data", common.ToHex(data), "height", cmt.Status.Height, "map", bitMap)
sign := g2pubs.Sign(data, client.blsPriKey).Serialize()
cmt.Bls = &pt.ParacrossCommitBlsInfo{Sign: sign[:], Addrs: bitMap}
}
return nil
}
//设置nodes范围内的bitmap,如果addrs在node不存在,也不设置,返回未命中的addrs
func setAddrsBitMap(nodes, addrs []string) ([]byte, map[string]bool) {
rst := big.NewInt(0)
addrsMap := make(map[string]bool)
for _, n := range addrs {
addrsMap[n] = true
}
for i, a := range nodes {
if _, exist := addrsMap[a]; exist {
rst.SetBit(rst, i, 1)
delete(addrsMap, a)
}
}
return rst.Bytes(), addrsMap
}
......@@ -7,6 +7,8 @@ package para
import (
"testing"
"encoding/hex"
"github.com/33cn/chain33/queue"
_ "github.com/33cn/chain33/system"
drivers "github.com/33cn/chain33/system/consensus"
......@@ -71,3 +73,10 @@ func TestSetSelfConsEnable(t *testing.T) {
assert.Equal(t, ep1, para.commitMsgClient.selfConsEnableList)
}
func TestSetAddrsBitMap(t *testing.T) {
nodes := []string{"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4", "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR", "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k", "1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"}
addrs := []string{"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"}
val, remain := setAddrsBitMap(nodes, addrs)
t.Log("val", hex.EncodeToString(val), "remain", remain)
}
......@@ -64,19 +64,21 @@ func TestCalcCommitMsgTxs(t *testing.T) {
Height: 2,
Title: "user.p.para",
}
notify := []*pt.ParacrossNodeStatus{nt1}
commit1 := &pt.ParacrossCommitAction{Status: nt1}
notify := []*pt.ParacrossCommitAction{commit1}
tx, count, err := client.calcCommitMsgTxs(notify, 0)
assert.Nil(t, err)
assert.Equal(t, int64(1), count)
assert.NotNil(t, tx)
notify = append(notify, nt2)
commit1 = &pt.ParacrossCommitAction{Status: nt2}
notify = append(notify, commit1)
tx, count, err = client.calcCommitMsgTxs(notify, 0)
assert.Nil(t, err)
assert.Equal(t, int64(2), count)
assert.NotNil(t, tx)
tx, err = client.singleCalcTx(nt2, 0)
tx, err = client.singleCalcTx(commit1, 0)
assert.Nil(t, err)
assert.NotNil(t, tx)
......
......@@ -496,7 +496,8 @@ function para_cross_transfer_withdraw_for_token() {
function para_create_nodegroup_gamechain() {
echo "=========== # game para chain create node group test ============="
##apply
txhash=$(${CLI} --paraName user.p.game. send para nodegroup apply -a "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4" -c 5 -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
local KS="0x8293f1e8eab2919910c2d347348d1d344a86e0dd10610ff06211f85c8cd3dfc99d81c36ef0f6ad6ba1db931d1ffbe7321411d80ce76269463301af5cce4128b196e48abced00c536f7be557fd5940ef5a0740c85a871fe81fe940aca9ed329e7"
txhash=$(${CLI} --paraName user.p.game. send para nodegroup apply -a "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4" -p "$KS" -c 5 -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
echo "tx=$txhash"
query_tx "${PARA_CLI5}" "${txhash}"
id=$txhash
......@@ -653,7 +654,13 @@ function para_create_nodegroup() {
echo "=========== # para chain create node group again ============="
##apply
txhash=$(${PARA_CLI} send para nodegroup apply -a "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY,1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4,1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR,1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k,1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs" -c 6 -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
local E5="0x9293f1e8eab2919910c2d347348d1d344a86e0dd10610ff06211f85c8cd3dfc99d81c36ef0f6ad6ba1db931d1ffbe7321411d80ce76269463301af5cce4128b196e48abced00c536f7be557fd5940ef5a0740c85a871fe81fe940aca9ed329e7"
local KS="0x8293f1e8eab2919910c2d347348d1d344a86e0dd10610ff06211f85c8cd3dfc99d81c36ef0f6ad6ba1db931d1ffbe7321411d80ce76269463301af5cce4128b196e48abced00c536f7be557fd5940ef5a0740c85a871fe81fe940aca9ed329e7"
local JR="0x8ed5ba075c27015e2c6da399b42da4cd272d4082b55f05c85d84b1308ec87bdb4aeea70dbef3e754eae99a6be0c0e49512d7e9197712f8538ce3d57c1b2d88e17b37f0e419f55333f6e841261a8d3151552fd7d4fd8e19f4f38a413395aab26e"
local NL="0x872e3ac07998deb12045ee48c52a8ba5d2538dc85123866fb330112eb0b805ce23f31bfde3a485cd89fac48eab48560005d12f714ca3786c7f47fe3b5edb1dc7838677c041c89cee4caf9225c1d68346bfcde3365ada0a627fbd77bc72e9b356"
local MC="0x87c58bb6cce41842462a0030335bb95948dcfba77e47e2d8ee893c0b2c34ac20d08c9e98a883ef2a6492d0ad808ace9a1730e8bae5d3b0861aaf743449df5de510073e2991c7274cab47f327e48d7eacf300e4b24174dae2e8603d1904b8a015"
local blspubs=$E5","$KS","$JR","$NL","$MC
txhash=$(${PARA_CLI} send para nodegroup apply -a "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY,1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4,1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR,1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k,1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs" -p "$blspubs" -c 6 -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
echo "tx=$txhash"
query_tx "${PARA_CLI}" "${txhash}"
id=$txhash
......
......@@ -327,6 +327,16 @@ func superNodeCmd() *cobra.Command {
return cmd
}
func nodeJoinCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "join",
Short: "super node apply for join nodegroup cmd",
Run: createNodeJoinTx,
}
addNodeJoinFlags(cmd)
return cmd
}
func addNodeJoinFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addr", "a", "", "target join addr")
cmd.MarkFlagRequired("addr")
......@@ -356,13 +366,13 @@ func createNodeJoinTx(cmd *cobra.Command, args []string) {
ctx.RunWithoutMarshal()
}
func nodeJoinCmd() *cobra.Command {
func nodeVoteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "join",
Short: "super node apply for join nodegroup cmd",
Run: createNodeJoinTx,
Use: "vote",
Short: "nodegroup nodes vote for new join node cmd",
Run: createNodeVoteTx,
}
addNodeJoinFlags(cmd)
addNodeVoteFlags(cmd)
return cmd
}
......@@ -395,13 +405,13 @@ func createNodeVoteTx(cmd *cobra.Command, args []string) {
}
func nodeVoteCmd() *cobra.Command {
func nodeQuitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "vote",
Short: "nodegroup nodes vote for new join node cmd",
Run: createNodeVoteTx,
Use: "quit",
Short: "super node apply for quit nodegroup cmd",
Run: createNodeQuitTx,
}
addNodeVoteFlags(cmd)
addNodeQuitFlags(cmd)
return cmd
}
......@@ -431,13 +441,13 @@ func createNodeQuitTx(cmd *cobra.Command, args []string) {
}
func nodeQuitCmd() *cobra.Command {
func nodeCancelCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "quit",
Short: "super node apply for quit nodegroup cmd",
Run: createNodeQuitTx,
Use: "cancel",
Short: "super node cancel join or quit action by id cmd",
Run: createNodeCancelTx,
}
addNodeQuitFlags(cmd)
addNodeCancelFlags(cmd)
return cmd
}
......@@ -467,16 +477,45 @@ func createNodeCancelTx(cmd *cobra.Command, args []string) {
}
func nodeCancelCmd() *cobra.Command {
func nodeModifyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cancel",
Short: "super node cancel join or quit action by id cmd",
Run: createNodeCancelTx,
Use: "modify",
Short: "super node modify parameters",
Run: createNodeModifyTx,
}
addNodeCancelFlags(cmd)
return cmd
}
func addNodeModifyFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addr", "a", "", "operating target apply id")
cmd.MarkFlagRequired("addr")
cmd.Flags().StringP("pubkey", "p", "", "operating target apply id")
cmd.MarkFlagRequired("pubkey")
}
func createNodeModifyTx(cmd *cobra.Command, args []string) {
paraName, _ := cmd.Flags().GetString("paraName")
addr, _ := cmd.Flags().GetString("addr")
pubkey, _ := cmd.Flags().GetString("pubkey")
if !strings.HasPrefix(paraName, "user.p") {
fmt.Fprintln(os.Stderr, "paraName is not right, paraName format like `user.p.guodun.`")
return
}
payload := &pt.ParaNodeAddrConfig{Title: paraName, Op: pt.ParaOpModify, Addr: addr, BlsPubKey: pubkey}
params := &rpctypes.CreateTxIn{
Execer: getRealExecName(paraName, pt.ParaX),
ActionName: "NodeConfig",
Payload: types.MustPBToJSON(payload),
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
// getNodeInfoCmd get node current status
func getNodeInfoCmd() *cobra.Command {
cmd := &cobra.Command{
......@@ -739,10 +778,22 @@ func nodeGroupCmd() *cobra.Command {
return cmd
}
func nodeGroupApplyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "apply",
Short: "apply for para chain's super node group",
Run: nodeGroupApply,
}
addNodeGroupApplyCmdFlags(cmd)
return cmd
}
func addNodeGroupApplyCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addrs", "a", "", "addrs apply for super node,split by ',' ")
cmd.MarkFlagRequired("addrs")
cmd.Flags().StringP("blspubs", "p", "", "bls sign pub key for addr's private key,split by ',' (optional)")
cmd.Flags().Float64P("coins", "c", 0, "coins amount to frozen, not less config")
cmd.MarkFlagRequired("coins")
......@@ -751,6 +802,7 @@ func addNodeGroupApplyCmdFlags(cmd *cobra.Command) {
func nodeGroupApply(cmd *cobra.Command, args []string) {
paraName, _ := cmd.Flags().GetString("paraName")
addrs, _ := cmd.Flags().GetString("addrs")
blspubs, _ := cmd.Flags().GetString("blspubs")
coins, _ := cmd.Flags().GetFloat64("coins")
if !strings.HasPrefix(paraName, "user.p") {
......@@ -758,7 +810,7 @@ func nodeGroupApply(cmd *cobra.Command, args []string) {
return
}
payload := &pt.ParaNodeGroupConfig{Title: paraName, Op: 1, Addrs: addrs, CoinsFrozen: int64(math.Trunc((coins+0.0000001)*1e4)) * 1e4}
payload := &pt.ParaNodeGroupConfig{Title: paraName, Op: 1, Addrs: addrs, BlsPubKeys: blspubs, CoinsFrozen: int64(math.Trunc((coins+0.0000001)*1e4)) * 1e4}
params := &rpctypes.CreateTxIn{
Execer: getRealExecName(paraName, pt.ParaX),
ActionName: "NodeGroupConfig",
......@@ -770,16 +822,6 @@ func nodeGroupApply(cmd *cobra.Command, args []string) {
ctx.RunWithoutMarshal()
}
func nodeGroupApplyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "apply",
Short: "apply for para chain's super node group",
Run: nodeGroupApply,
}
addNodeGroupApplyCmdFlags(cmd)
return cmd
}
func addNodeGroupApproveCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("id", "i", "", "apply id for nodegroup ")
cmd.MarkFlagRequired("id")
......
......@@ -17,6 +17,7 @@ import (
"github.com/33cn/chain33/util"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/golang/protobuf/proto"
"github.com/phoreproject/bls/g2pubs"
"github.com/pkg/errors"
)
......@@ -97,34 +98,37 @@ func validNode(addr string, nodes map[string]struct{}) bool {
return false
}
func checkCommitInfo(cfg *types.Chain33Config, commit *pt.ParacrossCommitAction) error {
if commit.Status == nil {
func checkCommitInfo(cfg *types.Chain33Config, commit *pt.ParacrossNodeStatus) error {
if commit == nil {
return types.ErrInvalidParam
}
clog.Debug("paracross.Commit check input", "height", commit.Status.Height, "mainHeight", commit.Status.MainBlockHeight,
"mainHash", common.ToHex(commit.Status.MainBlockHash), "blockHash", common.ToHex(commit.Status.BlockHash))
clog.Debug("paracross.Commit check input", "height", commit.Height, "mainHeight", commit.MainBlockHeight,
"mainHash", common.ToHex(commit.MainBlockHash), "blockHash", common.ToHex(commit.BlockHash))
if commit.Status.Height == 0 {
if len(commit.Status.Title) == 0 || len(commit.Status.BlockHash) == 0 {
if commit.Height == 0 {
if len(commit.Title) == 0 || len(commit.BlockHash) == 0 {
return types.ErrInvalidParam
}
return nil
}
if !pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if len(commit.Status.MainBlockHash) == 0 || len(commit.Status.Title) == 0 || commit.Status.Height < 0 ||
len(commit.Status.PreBlockHash) == 0 || len(commit.Status.BlockHash) == 0 ||
len(commit.Status.StateHash) == 0 || len(commit.Status.PreStateHash) == 0 {
if !pt.IsParaForkHeight(cfg, commit.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if len(commit.MainBlockHash) == 0 || len(commit.Title) == 0 || commit.Height < 0 ||
len(commit.PreBlockHash) == 0 || len(commit.BlockHash) == 0 ||
len(commit.StateHash) == 0 || len(commit.PreStateHash) == 0 {
return types.ErrInvalidParam
}
return nil
}
if len(commit.Status.MainBlockHash) == 0 || len(commit.Status.BlockHash) == 0 ||
commit.Status.MainBlockHeight < 0 || commit.Status.Height < 0 {
if len(commit.MainBlockHash) == 0 || len(commit.BlockHash) == 0 ||
commit.MainBlockHeight < 0 || commit.Height < 0 {
return types.ErrInvalidParam
}
if !validTitle(cfg, commit.Title) {
return pt.ErrInvalidTitle
}
return nil
}
......@@ -133,11 +137,11 @@ func isCommitDone(nodes map[string]struct{}, mostSame int) bool {
return 3*mostSame > 2*len(nodes)
}
func makeCommitReceipt(addr string, commit *pt.ParacrossCommitAction, prev, current *pt.ParacrossHeightStatus) *types.Receipt {
key := calcTitleHeightKey(commit.Status.Title, commit.Status.Height)
func makeCommitReceipt(addr string, commit *pt.ParacrossNodeStatus, prev, current *pt.ParacrossHeightStatus) *types.Receipt {
key := calcTitleHeightKey(commit.Title, commit.Height)
log := &pt.ReceiptParacrossCommit{
Addr: addr,
Status: commit.Status,
Status: commit,
Prev: prev,
Current: current,
}
......@@ -166,10 +170,10 @@ func makeCommitStatReceipt(current *pt.ParacrossHeightStatus) *types.Receipt {
}
}
func makeRecordReceipt(addr string, commit *pt.ParacrossCommitAction) *types.Receipt {
func makeRecordReceipt(addr string, commit *pt.ParacrossNodeStatus) *types.Receipt {
log := &pt.ReceiptParacrossRecord{
Addr: addr,
Status: commit.Status,
Status: commit,
}
return &types.Receipt{
Ty: types.ExecOk,
......@@ -262,35 +266,35 @@ func hasCommited(addrs []string, addr string) (bool, int) {
return false, 0
}
func getConfigNodes(db dbm.KV, title string) (map[string]struct{}, []byte, error) {
func getConfigNodes(db dbm.KV, title string) (map[string]struct{}, []string, []byte, error) {
key := calcParaNodeGroupAddrsKey(title)
nodes, _, err := getNodes(db, key)
nodes, nodesArray, err := getNodes(db, key)
if err != nil {
if errors.Cause(err) != pt.ErrTitleNotExist {
return nil, nil, errors.Wrapf(err, "getNodes para for title:%s", title)
return nil, nil, nil, errors.Wrapf(err, "getNodes para for title:%s", title)
}
key = calcManageConfigNodesKey(title)
nodes, _, err = getNodes(db, key)
nodes, nodesArray, err = getNodes(db, key)
if err != nil {
return nil, nil, errors.Wrapf(err, "getNodes manager for title:%s", title)
return nil, nil, nil, errors.Wrapf(err, "getNodes manager for title:%s", title)
}
}
return nodes, key, nil
return nodes, nodesArray, key, nil
}
func (a *action) getNodesGroup(title string) (map[string]struct{}, error) {
func (a *action) getNodesGroup(title string) (map[string]struct{}, []string, error) {
cfg := a.api.GetConfig()
if a.exec.GetMainHeight() < pt.GetDappForkHeight(cfg, pt.ForkCommitTx) {
nodes, _, err := getConfigManageNodes(a.db, title)
nodes, nodesArray, err := getConfigManageNodes(a.db, title)
if err != nil {
return nil, errors.Wrapf(err, "getNodes for title:%s", title)
return nil, nil, errors.Wrapf(err, "getNodes for title:%s", title)
}
return nodes, nil
return nodes, nodesArray, nil
}
nodes, _, err := getConfigNodes(a.db, title)
return nodes, err
nodes, nodesArray, _, err := getConfigNodes(a.db, title)
return nodes, nodesArray, err
}
......@@ -319,47 +323,50 @@ func updateCommitAddrs(stat *pt.ParacrossHeightStatus, nodes map[string]struct{}
}
func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
if cfg.IsPara() && cfg.IsDappFork(commit.Status.Height, pt.ParaX, pt.ForkParaSelfConsStages) {
//自共识分阶段使能,综合考虑挖矿奖励和共识分配奖励,判断是否自共识使能需要采用共识的高度,而不能采用当前区块高度a.height
//考虑自共识使能区块高度100,如果采用区块高度判断,则在100高度可能收到80~99的20条共识交易,这20条交易在100高度参与共识,则无奖励可分配,而且共识高度将是80而不是100
//采用共识高度commit.Status.Height判断,则严格执行了产生奖励和分配奖励,且共识高度从100开始
func paraCheckSelfConsOn(cfg *types.Chain33Config, db dbm.KV, commit *pt.ParacrossNodeStatus) (bool, *types.Receipt, error) {
if !cfg.IsDappFork(commit.Height, pt.ParaX, pt.ForkParaSelfConsStages) {
return true, nil, nil
}
//分叉之后,key不存在,自共识没配置也认为不支持自共识
isSelfConsOn, err := isSelfConsOn(a.db, commit.Status.Height)
isSelfConsOn, err := isSelfConsOn(db, commit.Height)
if err != nil && errors.Cause(err) != pt.ErrKeyNotExist {
return nil, err
return false, nil, err
}
if !isSelfConsOn {
clog.Debug("paracross.Commit self consens off", "height", commit.Status.Height)
return &types.Receipt{Ty: types.ExecOk}, nil
}
clog.Debug("paracross.Commit self consens off", "height", commit.Height)
return false, &types.Receipt{Ty: types.ExecOk}, nil
}
return true, nil, nil
}
func (a *action) preCheckCommitInfo(commit *pt.ParacrossNodeStatus) error {
cfg := a.api.GetConfig()
err := checkCommitInfo(cfg, commit)
if err != nil {
return nil, err
}
if !validTitle(cfg, commit.Status.Title) {
return nil, pt.ErrInvalidTitle
return err
}
nodes, err := a.getNodesGroup(commit.Status.Title)
nodesMap, _, err := a.getNodesGroup(commit.Title)
if err != nil {
return nil, err
return err
}
if !validNode(a.fromaddr, nodes) {
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "not validNode:%s", a.fromaddr)
if !validNode(a.fromaddr, nodesMap) {
return errors.Wrapf(pt.ErrNodeNotForTheTitle, "not validNode:%s", a.fromaddr)
}
titleStatus, err := getTitle(a.db, calcTitleKey(commit.Status.Title))
titleStatus, err := getTitle(a.db, calcTitleKey(commit.Title))
if err != nil {
return nil, errors.Wrapf(err, "getTitle:%s", a.fromaddr)
return errors.Wrapf(err, "getTitle:%s", a.fromaddr)
}
if titleStatus.Height+1 == commit.Status.Height && commit.Status.Height > 0 && !pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if !bytes.Equal(titleStatus.BlockHash, commit.Status.PreBlockHash) {
if titleStatus.Height+1 == commit.Height && commit.Height > 0 && !pt.IsParaForkHeight(cfg, commit.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if !bytes.Equal(titleStatus.BlockHash, commit.PreBlockHash) {
clog.Error("paracross.Commit", "check PreBlockHash", common.ToHex(titleStatus.BlockHash),
"commit tx", common.ToHex(commit.Status.PreBlockHash), "commitheit", commit.Status.Height,
"from", a.fromaddr)
return nil, pt.ErrParaBlockHashNoMatch
"commit tx", common.ToHex(commit.PreBlockHash), "commitheit", commit.Height, "from", a.fromaddr)
return pt.ErrParaBlockHashNoMatch
}
}
......@@ -369,41 +376,98 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
// 所以有必要做这个检测
var dbMainHash []byte
if !cfg.IsPara() {
blockHash, err := getBlockHash(a.api, commit.Status.MainBlockHeight)
blockHash, err := getBlockHash(a.api, commit.MainBlockHeight)
if err != nil {
clog.Error("paracross.Commit getBlockHash", "err", err,
"commit tx height", commit.Status.MainBlockHeight, "from", a.fromaddr)
return nil, err
clog.Error("paracross.Commit getBlockHash", "err", err, "commit tx height", commit.MainBlockHeight, "from", a.fromaddr)
return err
}
dbMainHash = blockHash.Hash
} else {
block, err := getBlockInfo(a.api, commit.Status.Height)
block, err := getBlockInfo(a.api, commit.Height)
if err != nil {
clog.Error("paracross.Commit getBlockInfo", "err", err, "height", commit.Status.Height, "from", a.fromaddr)
return nil, err
clog.Error("paracross.Commit getBlockInfo", "err", err, "height", commit.Height, "from", a.fromaddr)
return err
}
dbMainHash = block.MainHash
}
//对于主链,校验的是主链高度对应的blockhash是否和commit的一致
//对于平行链, 校验的是commit信息的平行链height block对应的mainHash是否和本地相同高度对应的mainHash一致, 在主链hash一致的时候看平行链共识blockhash是否一致
if !bytes.Equal(dbMainHash, commit.Status.MainBlockHash) && commit.Status.Height > 0 {
if !bytes.Equal(dbMainHash, commit.MainBlockHash) && commit.Height > 0 {
clog.Error("paracross.Commit blockHash not match", "isMain", !cfg.IsPara(), "db", common.ToHex(dbMainHash),
"commit", common.ToHex(commit.Status.MainBlockHash), "commitHeight", commit.Status.Height,
"commitMainHeight", commit.Status.MainBlockHeight, "from", a.fromaddr)
return nil, types.ErrBlockHashNoMatch
"commit", common.ToHex(commit.MainBlockHash), "commitHeight", commit.Height,
"commitMainHeight", commit.MainBlockHeight, "from", a.fromaddr)
return types.ErrBlockHashNoMatch
}
return nil
}
//共识commit msg 处理
func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
//平行链侧,自共识未使能则不处理
if cfg.IsPara() {
isSelfConsOn, receipt, err := paraCheckSelfConsOn(cfg, a.db, commit.Status)
if !isSelfConsOn {
return receipt, err
}
}
err := a.preCheckCommitInfo(commit.Status)
if err != nil {
return nil, err
}
if commit.Bls != nil {
return a.commitBls(commit)
}
return a.proCommitMsg(commit.Status, a.fromaddr)
}
//bls签名共识交易处理
func (a *action) commitBls(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
commitAddrs, err := a.verifyBlsSign(commit)
if err != nil {
clog.Error("paracross.Commit verifyBlsSign failed", "err", err)
return nil, err
}
receipt := &types.Receipt{Ty: types.ExecOk}
for _, addr := range commitAddrs {
r, err := a.proCommitMsg(commit.Status, addr)
if err != nil {
clog.Error("paracross.CommitBls proCommitMsg failed", "err", err)
return nil, err
}
receipt = mergeReceipt(receipt, r)
}
return receipt, nil
}
func (a *action) proCommitMsg(commit *pt.ParacrossNodeStatus, commitAddr string) (*types.Receipt, error) {
cfg := a.api.GetConfig()
nodes, _, err := a.getNodesGroup(commit.Title)
if err != nil {
return nil, err
}
titleStatus, err := getTitle(a.db, calcTitleKey(commit.Title))
if err != nil {
return nil, errors.Wrapf(err, "getTitle:%s", a.fromaddr)
}
clog.Debug("paracross.Commit check input done")
// 在完成共识之后来的, 增加 record log, 只记录不修改已经达成的共识
if commit.Status.Height <= titleStatus.Height {
clog.Debug("paracross.Commit record", "node", a.fromaddr, "titile", commit.Status.Title, "height", commit.Status.Height)
return makeRecordReceipt(a.fromaddr, commit), nil
if commit.Height <= titleStatus.Height {
clog.Debug("paracross.Commit record", "node", commitAddr, "titile", commit.Title, "height", commit.Height)
return makeRecordReceipt(commitAddr, commit), nil
}
// 未共识处理, 接受当前高度以及后续高度
stat, err := getTitleHeight(a.db, calcTitleHeightKey(commit.Status.Title, commit.Status.Height))
stat, err := getTitleHeight(a.db, calcTitleHeightKey(commit.Title, commit.Height))
if err != nil && !isNotFound(err) {
clog.Error("paracross.Commit getTitleHeight failed", "err", err)
return nil, err
......@@ -413,46 +477,46 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
if isNotFound(err) {
stat = &pt.ParacrossHeightStatus{
Status: pt.ParacrossStatusCommiting,
Title: commit.Status.Title,
Height: commit.Status.Height,
Title: commit.Title,
Height: commit.Height,
Details: &pt.ParacrossStatusDetails{
Addrs: []string{a.fromaddr},
BlockHash: [][]byte{commit.Status.BlockHash},
Addrs: []string{commitAddr},
BlockHash: [][]byte{commit.BlockHash},
},
}
if pt.IsParaForkHeight(cfg, a.exec.GetMainHeight(), pt.ForkCommitTx) {
stat.MainHeight = commit.Status.MainBlockHeight
stat.MainHash = commit.Status.MainBlockHash
stat.MainHeight = commit.MainBlockHeight
stat.MainHash = commit.MainBlockHash
}
//用commit.MainBlockHeight 判断更准确,如果用a.exec.MainHeight也可以,但是可能收到MainHeight之前的高度共识tx,
// 后面loopCommitTxDone时候也是用当前共识高度大于分叉高度判断
if pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if pt.IsParaForkHeight(cfg, commit.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
stat.BlockDetails = &pt.ParacrossStatusBlockDetails{}
updateCommitBlockHashs(stat, commit.Status)
updateCommitBlockHashs(stat, commit)
}
receipt = makeCommitReceipt(a.fromaddr, commit, nil, stat)
receipt = makeCommitReceipt(commitAddr, commit, nil, stat)
} else {
copyStat := proto.Clone(stat).(*pt.ParacrossHeightStatus)
// 如有分叉, 同一个节点可能再次提交commit交易
found, index := hasCommited(stat.Details.Addrs, a.fromaddr)
found, index := hasCommited(stat.Details.Addrs, commitAddr)
if found {
stat.Details.BlockHash[index] = commit.Status.BlockHash
if pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
updateCommitBlockHashs(stat, commit.Status)
stat.Details.BlockHash[index] = commit.BlockHash
if pt.IsParaForkHeight(cfg, commit.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
updateCommitBlockHashs(stat, commit)
}
} else {
stat.Details.Addrs = append(stat.Details.Addrs, a.fromaddr)
stat.Details.BlockHash = append(stat.Details.BlockHash, commit.Status.BlockHash)
if pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
updateCommitBlockHashs(stat, commit.Status)
stat.Details.Addrs = append(stat.Details.Addrs, commitAddr)
stat.Details.BlockHash = append(stat.Details.BlockHash, commit.BlockHash)
if pt.IsParaForkHeight(cfg, commit.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
updateCommitBlockHashs(stat, commit)
}
}
receipt = makeCommitReceipt(a.fromaddr, commit, copyStat, stat)
receipt = makeCommitReceipt(commitAddr, commit, copyStat, stat)
}
//平行链fork pt.ForkCommitTx=0,主链在ForkCommitTx后支持nodegroup,这里平行链dappFork一定为true
if cfg.IsDappFork(commit.Status.MainBlockHeight, pt.ParaX, pt.ForkCommitTx) {
if cfg.IsDappFork(commit.MainBlockHeight, pt.ParaX, pt.ForkCommitTx) {
updateCommitAddrs(stat, nodes)
}
saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
......@@ -462,8 +526,8 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
receipt = mergeReceipt(receipt, r)
}
if commit.Status.Height > titleStatus.Height+1 {
saveTitleHeight(a.db, calcTitleHeightKey(commit.Status.Title, commit.Status.Height), stat)
if commit.Height > titleStatus.Height+1 {
saveTitleHeight(a.db, calcTitleHeightKey(commit.Title, commit.Height), stat)
//平行链由主链共识无缝切换,即接收第一个收到的高度,可以不从0开始
allow, err := a.isAllowConsensJump(commit, titleStatus)
if err != nil {
......@@ -474,7 +538,7 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
return receipt, nil
}
}
r, err := a.commitTxDone(commit.Status, stat, titleStatus, nodes)
r, err := a.commitTxDone(commit, stat, titleStatus, nodes)
if err != nil {
return nil, err
}
......@@ -482,6 +546,64 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
return receipt, nil
}
func (a *action) verifyBlsSign(commit *pt.ParacrossCommitAction) ([]string, error) {
_, nodesArry, err := a.getNodesGroup(commit.Status.Title)
if err != nil {
return nil, err
}
//1. 获取addr对应的bls 公钥
signAddrs := getAddrsByBitMap(nodesArry, commit.Bls.Addrs)
var pubs []string
for _, addr := range signAddrs {
pub, err := getAddrBlsPubKey(a.db, commit.Status.Title, addr)
if err != nil {
clog.Error("verifyBlsSign pub key not exist", "addr", addr)
return nil, err
}
pubs = append(pubs, pub)
}
pubKeys := make([]*g2pubs.PublicKey, 0)
for _, p := range pubs {
k := [96]byte{}
val, err := common.FromHex(p)
if err != nil {
clog.Error("verifyBlsSign.fromhex", "p", p)
return nil, err
}
copy(k[:], val)
key, err := g2pubs.DeserializePublicKey(k)
if err != nil {
clog.Error("verifyBlsSign.DeserializePublicKey", "key", p)
return nil, err
}
pubKeys = append(pubKeys, key)
}
//2. 聚合公钥
aPub := g2pubs.AggregatePublicKeys(pubKeys)
//3. 获取聚合的签名
signkey := [48]byte{}
copy(signkey[:], commit.Bls.Sign)
sign, err := g2pubs.DeserializeSignature(signkey)
if err != nil {
clog.Error("verifyBlsSign.DeserializeSignature", "key", common.ToHex(commit.Bls.Sign))
return nil, err
}
//4. 获取签名前原始msg
msg := types.Encode(commit.Status)
if !g2pubs.Verify(msg, aPub, sign) {
clog.Error("paracross.Commit bls sign verify", "title", commit.Status.Title, "height", commit.Status.Height,
"addrsMap", common.ToHex(commit.Bls.Addrs), "sign", common.ToHex(commit.Bls.Sign), "addr", signAddrs, "nodes", nodesArry)
clog.Error("paracross.commit bls sign verify", "data", common.ToHex(msg), "height", commit.Status.Height)
return nil, pt.ErrBlsSignVerify
}
return signAddrs, nil
}
//分叉以前stat里面只记录了blockhash的信息,没有crossTxHash等信息,无法通过stat直接重构出mostCommitStatus
func (a *action) commitTxDone(nodeStatus *pt.ParacrossNodeStatus, stat *pt.ParacrossHeightStatus, titleStatus *pt.ParacrossStatus,
nodes map[string]struct{}) (*types.Receipt, error) {
......@@ -706,7 +828,7 @@ func (a *action) commitTxDoneByStat(stat *pt.ParacrossHeightStatus, titleStatus
}
//主链共识跳跃条件: 仅支持主链共识初始高度为-1,也就是没有共识过,共识过不允许再跳跃
func (a *action) isAllowMainConsensJump(commit *pt.ParacrossCommitAction, titleStatus *pt.ParacrossStatus) bool {
func (a *action) isAllowMainConsensJump(commit *pt.ParacrossNodeStatus, titleStatus *pt.ParacrossStatus) bool {
cfg := a.api.GetConfig()
if cfg.IsDappFork(a.exec.GetMainHeight(), pt.ParaX, pt.ForkLoopCheckCommitTxDone) {
if titleStatus.Height == -1 {
......@@ -720,24 +842,24 @@ func (a *action) isAllowMainConsensJump(commit *pt.ParacrossCommitAction, titleS
//平行链自共识无缝切换条件:1,平行链没有共识过,2:commit高度是大于自共识分叉高度且上一次共识的主链高度小于自共识分叉高度,保证只运行一次,
// 1. 分叉之前,开启过共识的平行链需要从1跳跃,没开启过的将使用新版本,从0开始发送,不用考虑从1跳跃的问题
// 2. 分叉之后,只有stage.blockHeight== commit.height,也就是stage起始高度时候允许跳跃
func (a *action) isAllowParaConsensJump(commit *pt.ParacrossCommitAction, titleStatus *pt.ParacrossStatus) (bool, error) {
func (a *action) isAllowParaConsensJump(commit *pt.ParacrossNodeStatus, titleStatus *pt.ParacrossStatus) (bool, error) {
cfg := a.api.GetConfig()
if cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaSelfConsStages) {
stage, err := getSelfConsOneStage(a.db, commit.Status.Height)
stage, err := getSelfConsOneStage(a.db, commit.Height)
if err != nil && errors.Cause(err) != pt.ErrKeyNotExist {
return false, err
}
if stage == nil {
return false, nil
}
return stage.StartHeight == commit.Status.Height, nil
return stage.StartHeight == commit.Height, nil
}
//兼容分叉之前从1跳跃场景
return titleStatus.Height == -1, nil
}
func (a *action) isAllowConsensJump(commit *pt.ParacrossCommitAction, titleStatus *pt.ParacrossStatus) (bool, error) {
func (a *action) isAllowConsensJump(commit *pt.ParacrossNodeStatus, titleStatus *pt.ParacrossStatus) (bool, error) {
cfg := a.api.GetConfig()
if cfg.IsPara() {
return a.isAllowParaConsensJump(commit, titleStatus)
......@@ -1145,6 +1267,9 @@ func (a *action) Miner(miner *pt.ParacrossMinerAction) (*types.Receipt, error) {
logs = append(logs, log)
minerReceipt := &types.Receipt{Ty: types.ExecOk, KV: nil, Logs: logs}
//自共识分阶段使能,综合考虑挖矿奖励和共识分配奖励,判断是否自共识使能需要采用共识的高度,而不能采用当前区块高度a.height
//考虑自共识使能区块高度100,如果采用区块高度判断,则在100高度可能收到80~99的20条共识交易,这20条交易在100高度参与共识,则无奖励可分配,而且共识高度将是80而不是100
//采用共识高度miner.Status.Height判断,则严格执行了产生奖励和分配奖励,且共识高度从100开始
isSelfConsensOn := miner.IsSelfConsensus
if cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaSelfConsStages) {
var err error
......@@ -1200,7 +1325,7 @@ func (a *action) isAllowTransfer() error {
if err != nil {
return errors.Wrapf(types.ErrInvalidParam, "not para chain exec=%s", string(a.tx.Execer))
}
nodes, err := a.getNodesGroup(string(tempTitle))
nodes, _, err := a.getNodesGroup(string(tempTitle))
if err != nil {
return errors.Wrapf(err, "nodegroup not config,title=%s", tempTitle)
}
......
......@@ -122,14 +122,14 @@ func (a *action) crossAssetTransfer(transfer *pt.CrossAssetTransfer, act int64,
return nil, err
}
clog.Info("paracross.crossAssetTransfer", "action", act, "newExec", newTransfer.AssetExec, "newSymbol", newTransfer.AssetSymbol,
"ori.exec", transfer.AssetExec, "ori.symbol", transfer.AssetSymbol, "txHash", common.ToHex(a.tx.Hash()))
"ori.exec", transfer.AssetExec, "ori.symbol", transfer.AssetSymbol, "txHash", common.ToHex(actTx.Hash()))
switch act {
case pt.ParacrossMainAssetTransfer:
return a.mainAssetTransfer(newTransfer)
return a.mainAssetTransfer(newTransfer, actTx)
case pt.ParacrossMainAssetWithdraw:
return a.mainAssetWithdraw(newTransfer, actTx)
case pt.ParacrossParaAssetTransfer:
return a.paraAssetTransfer(newTransfer)
return a.paraAssetTransfer(newTransfer, actTx)
case pt.ParacrossParaAssetWithdraw:
return a.paraAssetWithdraw(newTransfer, actTx)
default:
......@@ -138,14 +138,14 @@ func (a *action) crossAssetTransfer(transfer *pt.CrossAssetTransfer, act int64,
}
//主链先transfer, 然后平行链create asset, 如果平行链失败,主链再rollback
func (a *action) mainAssetTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
func (a *action) mainAssetTransfer(transfer *pt.CrossAssetTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支, 先处理
if !isPara {
return a.execTransfer(transfer)
return a.execTransfer(transfer, transferTx)
}
return a.execCreateAsset(transfer)
return a.execCreateAsset(transfer, transferTx)
}
//平行链先销毁, 共识后主链再withdraw
......@@ -156,19 +156,19 @@ func (a *action) mainAssetWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *
if !isPara {
return a.execWithdraw(withdraw, withdrawTx)
}
return a.execDestroyAsset(withdraw)
return a.execDestroyAsset(withdraw, withdrawTx)
}
//平行链先转移, 共识后主链create asset
func (a *action) paraAssetTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
func (a *action) paraAssetTransfer(transfer *pt.CrossAssetTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//平行链链处理分支,先处理
if isPara {
return a.execTransfer(transfer)
return a.execTransfer(transfer, transferTx)
}
//主链共识后处理
return a.execCreateAsset(transfer)
return a.execCreateAsset(transfer, transferTx)
}
//平行链从主链提回, 先在主链处理,然后在平行链处理, 如果平行链执行失败,共识后主链再回滚
......@@ -179,10 +179,10 @@ func (a *action) paraAssetWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *
if isPara {
return a.execWithdraw(withdraw, withdrawTx)
}
return a.execDestroyAsset(withdraw)
return a.execDestroyAsset(withdraw, withdrawTx)
}
func (a *action) execTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
func (a *action) execTransfer(transfer *pt.CrossAssetTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
accDB, err := a.createAccount(cfg, a.db, transfer.AssetExec, transfer.AssetSymbol)
if err != nil {
......@@ -191,30 +191,30 @@ func (a *action) execTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt,
//主链上存入toAddr为user.p.xx.paracross地址
execAddr := address.ExecAddress(pt.ParaX)
toAddr := address.ExecAddress(string(a.tx.Execer))
toAddr := address.ExecAddress(string(transferTx.Execer))
//在平行链上存入toAddr为paracross地址
if cfg.IsPara() {
execAddr = address.ExecAddress(string(a.tx.Execer))
execAddr = address.ExecAddress(string(transferTx.Execer))
toAddr = address.ExecAddress(pt.ParaX)
}
clog.Debug("paracross.execTransfer", "execer", string(a.tx.Execer), "assetexec", transfer.AssetExec, "symbol", transfer.AssetSymbol,
"txHash", common.ToHex(a.tx.Hash()))
clog.Debug("paracross.execTransfer", "execer", string(transferTx.Execer), "assetexec", transfer.AssetExec, "symbol", transfer.AssetSymbol,
"txHash", common.ToHex(transferTx.Hash()))
//对于paracross合约下的资产直接转账,不需要通过存到paracross合约下再转账,这里只有主链的A平行链资产转移到另一个B平行链场景
if transfer.AssetExec == pt.ParaX {
r, err := accDB.Transfer(a.fromaddr, toAddr, transfer.Amount)
r, err := accDB.Transfer(transferTx.From(), toAddr, transfer.Amount)
if err != nil {
return nil, errors.Wrapf(err, "assetTransfer,assetExec=%s,assetSym=%s", transfer.AssetExec, transfer.AssetSymbol)
}
return r, nil
}
fromAcc := accDB.LoadExecAccount(a.fromaddr, execAddr)
fromAcc := accDB.LoadExecAccount(transferTx.From(), execAddr)
if fromAcc.Balance < transfer.Amount {
return nil, errors.Wrapf(types.ErrNoBalance, "execTransfer,acctBalance=%d,assetExec=%s,assetSym=%s", fromAcc.Balance, transfer.AssetExec, transfer.AssetSymbol)
}
r, err := accDB.ExecTransfer(a.fromaddr, toAddr, execAddr, transfer.Amount)
r, err := accDB.ExecTransfer(transferTx.From(), toAddr, execAddr, transfer.Amount)
if err != nil {
return nil, errors.Wrapf(err, "assetTransfer,assetExec=%s,assetSym=%s", transfer.AssetExec, transfer.AssetSymbol)
}
......@@ -236,7 +236,7 @@ func (a *action) execWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *types
}
clog.Debug("Paracross.execWithdraw", "amount", withdraw.Amount, "from", fromAddr,
"assetExec", withdraw.AssetExec, "symbol", withdraw.AssetSymbol, "execAddr", execAddr, "txHash", common.ToHex(a.tx.Hash()))
"assetExec", withdraw.AssetExec, "symbol", withdraw.AssetSymbol, "execAddr", execAddr, "txHash", common.ToHex(withdrawTx.Hash()))
//对于paracross合约下的资产直接转账,不需要通过存到paracross合约下再转账,这里只有主链的A平行链资产转移到另一个B平行链场景
if withdraw.AssetExec == pt.ParaX {
......@@ -257,11 +257,11 @@ func (a *action) execWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *types
//主链Alice的token转移到user.p.bb.平行链,在平行链上表示为mavl-paracross-token.symbol-Addr(Alice),这里并没有放在Addr(user.p.bb.paracross)子账号下
//平行链转移到主链的token在主链表示为mavl-paracross-user.p.aa.token.symbol-exec-Addr(Alice),再转移到另一个user.p.bb.平行链,需要先transfer到paracross执行器下
//在平行链bb上铸造新币,表示为mavl-paracross-paracross.user.p.aa.token.symbol-exec-Addr(Alice),第二个paracross代表在主链原生执行器为paracross
func (a *action) createParaAccount(cross *pt.CrossAssetTransfer) (*account.DB, error) {
func (a *action) createParaAccount(cross *pt.CrossAssetTransfer, crossTx *types.Transaction) (*account.DB, error) {
cfg := a.api.GetConfig()
paraTitle, err := getTitleFrom(a.tx.Execer)
paraTitle, err := getTitleFrom(crossTx.Execer)
if err != nil {
return nil, errors.Wrapf(err, "createParaAccount call getTitleFrom failed,exec=%s", string(a.tx.Execer))
return nil, errors.Wrapf(err, "createParaAccount call getTitleFrom failed,exec=%s", string(crossTx.Execer))
}
assetExec := cross.AssetExec
......@@ -270,20 +270,20 @@ func (a *action) createParaAccount(cross *pt.CrossAssetTransfer) (*account.DB, e
assetExec = string(paraTitle) + assetExec
}
paraAcc, err := NewParaAccount(cfg, string(paraTitle), assetExec, assetSymbol, a.db)
clog.Debug("createParaAccount", "assetExec", assetExec, "symbol", assetSymbol, "txHash", common.ToHex(a.tx.Hash()))
clog.Debug("createParaAccount", "assetExec", assetExec, "symbol", assetSymbol, "txHash", common.ToHex(crossTx.Hash()))
if err != nil {
return nil, errors.Wrapf(err, "createParaAccount,exec=%s,symbol=%s,title=%s", assetExec, assetSymbol, paraTitle)
}
return paraAcc, nil
}
func (a *action) execCreateAsset(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
paraAcc, err := a.createParaAccount(transfer)
func (a *action) execCreateAsset(transfer *pt.CrossAssetTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
paraAcc, err := a.createParaAccount(transfer, transferTx)
if err != nil {
return nil, errors.Wrapf(err, "createAsset")
}
clog.Debug("paracross.execCreateAsset", "assetExec", transfer.AssetExec, "symbol", transfer.AssetSymbol,
"txHash", common.ToHex(a.tx.Hash()))
"txHash", common.ToHex(transferTx.Hash()))
r, err := assetDepositBalance(paraAcc, transfer.ToAddr, transfer.Amount)
if err != nil {
......@@ -292,14 +292,14 @@ func (a *action) execCreateAsset(transfer *pt.CrossAssetTransfer) (*types.Receip
return r, nil
}
func (a *action) execDestroyAsset(withdraw *pt.CrossAssetTransfer) (*types.Receipt, error) {
paraAcc, err := a.createParaAccount(withdraw)
func (a *action) execDestroyAsset(withdraw *pt.CrossAssetTransfer, withdrawTx *types.Transaction) (*types.Receipt, error) {
paraAcc, err := a.createParaAccount(withdraw, withdrawTx)
if err != nil {
return nil, errors.Wrapf(err, "destroyAsset")
}
clog.Debug("paracross.execDestroyAsset", "assetExec", withdraw.AssetExec, "symbol", withdraw.AssetSymbol,
"txHash", common.ToHex(a.tx.Hash()), "from", a.fromaddr, "amount", withdraw.Amount)
r, err := assetWithdrawBalance(paraAcc, a.fromaddr, withdraw.Amount)
"txHash", common.ToHex(withdrawTx.Hash()), "from", withdrawTx.From(), "amount", withdraw.Amount)
r, err := assetWithdrawBalance(paraAcc, withdrawTx.From(), withdraw.Amount)
if err != nil {
return nil, errors.Wrapf(err, "destroyAsset,assetExec=%s,assetSym=%s", withdraw.AssetExec, withdraw.AssetSymbol)
}
......@@ -315,7 +315,7 @@ func (a *action) assetTransfer(transfer *types.AssetsTransfer) (*types.Receipt,
ToAddr: transfer.To,
}
adaptNullAssetExec(tr)
return a.mainAssetTransfer(tr)
return a.mainAssetTransfer(tr, a.tx)
}
//旧的接口,只有主链从平行链转移
......@@ -363,7 +363,7 @@ func (a *action) paraAssetWithdrawRollback(wtw *pt.CrossAssetTransfer, withdrawT
if err != nil {
return nil, errors.Wrapf(err, "paraAssetWithdrawRollback amend param")
}
paraAcc, err := a.createParaAccount(withdraw)
paraAcc, err := a.createParaAccount(withdraw, withdrawTx)
if err != nil {
return nil, errors.Wrapf(err, "createAsset")
}
......
......@@ -6,7 +6,6 @@ package executor
import (
"encoding/hex"
"fmt"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
......@@ -78,17 +77,21 @@ func (p *Paracross) Query_GetNodeGroupAddrs(in *pt.ReqParacrossNodeInfo) (types.
return nil, errors.Wrap(types.ErrInvalidParam, "title is null")
}
ret, key, err := getConfigNodes(p.GetStateDB(), in.GetTitle())
_, nodesArry, key, err := getConfigNodes(p.GetStateDB(), in.GetTitle())
if err != nil {
return nil, err
}
var nodes []string
for k := range ret {
nodes = append(nodes, k)
var nodes string
for _, k := range nodesArry {
if len(nodes) == 0 {
nodes = k
continue
}
nodes = nodes + "," + k
}
var reply types.ReplyConfig
reply.Key = string(key)
reply.Value = fmt.Sprint(nodes)
reply.Value = nodes
return &reply, nil
}
......
......@@ -9,6 +9,8 @@ import (
"strconv"
"math/big"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
......@@ -208,6 +210,28 @@ func makeParaNodeGroupReceipt(title string, prev, current *types.ConfigItem) *ty
}
}
//获取nodes范围内的bitmap,如果bitmap超出了nodes范围,也不处理,防止越界
func getAddrsByBitMap(nodes []string, bitmap []byte) []string {
rst := big.NewInt(0).SetBytes(bitmap)
addrs := make([]string, 0)
for i, a := range nodes {
if rst.Bit(i) == uint(0x1) {
addrs = append(addrs, a)
}
}
return addrs
}
//get secp256 addr's bls pubkey
func getAddrBlsPubKey(db dbm.KV, title, addr string) (string, error) {
addrStat, err := getNodeAddr(db, title, addr)
if err != nil {
return "", errors.Wrapf(err, "nodeAddr:%s-%s get error", title, addr)
}
return addrStat.BlsPubKey, nil
}
func (a *action) checkValidNode(config *pt.ParaNodeAddrConfig) (bool, error) {
nodes, _, err := getParacrossNodes(a.db, config.Title)
if err != nil {
......@@ -262,6 +286,7 @@ func (a *action) nodeJoin(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
Status: pt.ParaApplyJoining,
Title: config.Title,
TargetAddr: config.Addr,
BlsPubKey: config.BlsPubKey,
FromAddr: a.fromaddr,
Votes: &pt.ParaNodeVoteDetail{},
CoinsFrozen: config.CoinsFrozen,
......@@ -350,6 +375,23 @@ func (a *action) nodeCancel(config *pt.ParaNodeAddrConfig) (*types.Receipt, erro
}
func (a *action) nodeModify(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
addrStat, err := getNodeAddr(a.db, config.Title, config.Addr)
if err != nil {
return nil, errors.Wrapf(err, "nodeAddr:%s get error", config.Addr)
}
//只能提案发起人撤销
if a.fromaddr != config.Addr {
return nil, errors.Wrapf(types.ErrNotAllow, "addr create by:%s,not by:%s", config.Addr, a.fromaddr)
}
preStat := *addrStat
addrStat.BlsPubKey = config.BlsPubKey
return makeParaNodeStatusReceipt(a.fromaddr, &preStat, addrStat), nil
}
// IsSuperManager is supper manager or not
func isSuperManager(cfg *types.Chain33Config, addr string) bool {
confManager := types.ConfSub(cfg, manager.ManageX)
......@@ -439,6 +481,7 @@ func (a *action) updateNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*types.Receipt
addrStat = &pt.ParaNodeAddrIdStatus{}
addrStat.Title = stat.Title
addrStat.Addr = stat.TargetAddr
addrStat.BlsPubKey = stat.BlsPubKey
addrStat.Status = pt.ParaApplyJoined
addrStat.ProposalId = stat.Id
addrStat.QuitId = ""
......@@ -769,6 +812,15 @@ func (a *action) nodeGroupApply(config *pt.ParaNodeGroupConfig) (*types.Receipt,
return nil, errors.Wrapf(types.ErrInvalidParam, "node group apply addrs null:%s", config.Addrs)
}
var blsPubKeys []string
if len(config.BlsPubKeys) > 0 {
blsPubKeys = getConfigAddrs(config.BlsPubKeys)
if len(blsPubKeys) != len(addrs) {
return nil, errors.Wrapf(types.ErrInvalidParam, "nodegroup apply blsPubkeys length=%d not match addrs=%d",
len(blsPubKeys), len(addrs))
}
}
receipt := &types.Receipt{Ty: types.ExecOk}
//main chain
cfg := a.api.GetConfig()
......@@ -787,9 +839,12 @@ func (a *action) nodeGroupApply(config *pt.ParaNodeGroupConfig) (*types.Receipt,
Status: pt.ParacrossNodeGroupApply,
Title: config.Title,
TargetAddrs: strings.Join(addrs, ","),
BlsPubKeys: strings.Join(blsPubKeys, ","),
CoinsFrozen: config.CoinsFrozen,
FromAddr: a.fromaddr,
Height: a.height}
Height: a.height,
}
r := makeNodeGroupIDReceipt(a.fromaddr, nil, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
......@@ -977,6 +1032,11 @@ func (a *action) nodeGroupCreate(status *pt.ParaNodeGroupStatus) (*types.Receipt
receipt := makeParaNodeGroupReceipt(status.Title, nil, &item)
var blsPubKeys []string
if len(status.BlsPubKeys) > 0 {
blsPubKeys = strings.Split(status.BlsPubKeys, ",")
}
//update addr status
for i, addr := range nodes {
stat := &pt.ParaNodeIdStatus{
......@@ -988,7 +1048,9 @@ func (a *action) nodeGroupCreate(status *pt.ParaNodeGroupStatus) (*types.Receipt
CoinsFrozen: status.CoinsFrozen,
FromAddr: status.FromAddr,
Height: a.height}
if len(blsPubKeys) > 0 {
stat.BlsPubKey = blsPubKeys[i]
}
r := makeNodeConfigReceipt(a.fromaddr, nil, nil, stat)
receipt = mergeReceipt(receipt, r)
......@@ -1052,25 +1114,28 @@ func (a *action) NodeConfig(config *pt.ParaNodeAddrConfig) (*types.Receipt, erro
return nil, errors.Wrapf(types.ErrInvalidParam, "exec=%s,should prefix with user.p.", string(a.tx.Execer))
}
if config.Op == pt.ParaOpNewApply {
switch config.Op {
case pt.ParaOpNewApply:
return a.nodeJoin(config)
} else if config.Op == pt.ParaOpQuit {
case pt.ParaOpQuit:
//退出nodegroup
return a.nodeQuit(config)
} else if config.Op == pt.ParaOpCancel {
case pt.ParaOpCancel:
//撤销未批准的申请
if config.Id == "" {
return nil, types.ErrInvalidParam
}
return a.nodeCancel(config)
} else if config.Op == pt.ParaOpVote {
case pt.ParaOpVote:
if config.Id == "" || config.Value >= pt.ParaVoteEnd {
return nil, types.ErrInvalidParam
}
return a.nodeVote(config)
}
case pt.ParaOpModify:
//修改addr相关联的参数,只能原创地址修改
return a.nodeModify(config)
default:
return nil, pt.ErrParaUnSupportNodeOper
}
}
......@@ -61,6 +61,7 @@ message ParaNodeAddrConfig {
string addr = 4;
uint32 value = 5;
int64 coinsFrozen = 6;
string blsPubKey = 7; //本地址私钥对应的bls聚合签名的公钥
}
message ParaNodeVoteDetail {
......@@ -74,6 +75,7 @@ message ParaNodeAddrIdStatus {
string quitId = 3;
int32 status = 4;
string title = 5;
string blsPubKey = 6;
}
message ParaNodeIdStatus {
......@@ -85,6 +87,7 @@ message ParaNodeIdStatus {
ParaNodeVoteDetail votes = 6;
string fromAddr = 7;
int64 height = 8;
string blsPubKey = 9;
}
message ReceiptParaNodeConfig {
......@@ -117,6 +120,7 @@ message ParaNodeGroupConfig {
string id = 3;
string addrs = 4;
int64 coinsFrozen = 5;
string blsPubKeys = 6;
}
message ParaNodeGroupStatus {
......@@ -127,6 +131,7 @@ message ParaNodeGroupStatus {
int64 coinsFrozen = 5;
string fromAddr = 6;
int64 height = 7;
string blsPubKeys = 8;
}
message ReceiptParaNodeGroupConfig {
......@@ -142,6 +147,7 @@ message ReqParacrossNodeInfo {
string id = 2;
string addr = 3;
int32 status = 4;
string blsPubKey = 5;
}
message RespParacrossNodeAddrs {
......@@ -259,8 +265,14 @@ message ReplyQuerySelfStages {
repeated SelfConsensStageInfo stageInfo = 1;
}
message ParacrossCommitBlsInfo {
bytes sign = 1;
bytes addrs = 2; //addrs' bitmap
}
message ParacrossCommitAction {
ParacrossNodeStatus status = 1;
ParacrossCommitBlsInfo bls = 2;
}
message ParacrossMinerAction {
......
......@@ -57,4 +57,6 @@ var (
ErrKeyNotExist = errors.New("ErrKeyNotExist")
// ErrConsensClosed consensus closed
ErrConsensClosed = errors.New("ErrConsensClosed")
//ErrConsBlsSignVerify bls12-381 aggregate sign verify
ErrBlsSignVerify = errors.New("ErrBlsSignVerify")
)
......@@ -105,6 +105,7 @@ const (
ParaOpVote
ParaOpQuit
ParaOpCancel
ParaOpModify
)
// node vote op
......@@ -180,17 +181,14 @@ func CalcMinerHeightKey(title string, height int64) []byte {
}
// CreateRawCommitTx4MainChain create commit tx to main chain
func CreateRawCommitTx4MainChain(cfg *types.Chain33Config, status *ParacrossNodeStatus, name string, fee int64) (*types.Transaction, error) {
func CreateRawCommitTx4MainChain(cfg *types.Chain33Config, status *ParacrossCommitAction, name string, fee int64) (*types.Transaction, error) {
return createRawCommitTx(cfg, status, name, fee)
}
func createRawCommitTx(cfg *types.Chain33Config, status *ParacrossNodeStatus, name string, feeRate int64) (*types.Transaction, error) {
v := &ParacrossCommitAction{
Status: status,
}
func createRawCommitTx(cfg *types.Chain33Config, commit *ParacrossCommitAction, name string, feeRate int64) (*types.Transaction, error) {
action := &ParacrossAction{
Ty: ParacrossActionCommit,
Value: &ParacrossAction_Commit{v},
Value: &ParacrossAction_Commit{commit},
}
tx := &types.Transaction{
Execer: []byte(name),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment