From: mars Date: Tue, 27 Nov 2018 13:24:48 +0000 (+0800) Subject: add pegin address for contract X-Git-Tag: v1.0.5~223^2~2^2~1 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=daba4101f8c0712a5976e7431dbc6a650d02bb82 add pegin address for contract --- diff --git a/account/accounts.go b/account/accounts.go index 503939b4..eb6474a4 100644 --- a/account/accounts.go +++ b/account/accounts.go @@ -2,7 +2,10 @@ package account import ( + "crypto/hmac" + "crypto/sha256" "encoding/json" + "fmt" "reflect" "sort" "strings" @@ -18,8 +21,11 @@ import ( "github.com/vapor/consensus" "github.com/vapor/consensus/segwit" "github.com/vapor/crypto" + "github.com/vapor/crypto/ed25519" "github.com/vapor/crypto/ed25519/chainkd" "github.com/vapor/crypto/sha3pool" + chainjson "github.com/vapor/encoding/json" + "github.com/vapor/equity/compiler" "github.com/vapor/errors" "github.com/vapor/protocol" "github.com/vapor/protocol/bc" @@ -808,7 +814,64 @@ func (m *Manager) GetPeginControlPrograms(claimScript []byte) (string, []byte) { federationRedeemScript := vmutil.CalculateContract(consensus.ActiveNetParams.FedpegXPubs, claimScript) scriptHash := crypto.Sha256(federationRedeemScript) - address, err := common.NewAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams) + address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams) + if err != nil { + return "", nil + } + + redeemContract := address.ScriptAddress() + + program := []byte{} + program, err = vmutil.P2WSHProgram(redeemContract) + if err != nil { + return "", nil + } + + return address.EncodeAddress(), program +} + +var lockWith2of3KeysFmt = ` +contract LockWith3Keys(%s) locks amount of asset { + clause unlockWith2Sigs(%s) { + verify checkTxMultiSig(%s) + unlock amount of asset + } +} +` + +func (m *Manager) CreatePeginContractAddress(accountID string, change bool) (string, []byte, error) { + // 通过配置获取 + claimCtrlProg, err := m.CreateAddress(accountID, change) + if err != nil { + return "", nil, err + } + claimScript := claimCtrlProg.ControlProgram + + peginContractPrograms, err := m.getPeginContractPrograms(claimScript) + if err != nil { + return "", nil, err + } + + scriptHash := crypto.Sha256(peginContractPrograms) + + address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams) + if err != nil { + return "", nil, err + } + + return address.EncodeAddress(), claimScript, nil + +} + +func (m *Manager) GetPeginContractControlPrograms(claimScript []byte) (string, []byte) { + + peginContractPrograms, err := m.getPeginContractPrograms(claimScript) + if err != nil { + return "", nil + } + scriptHash := crypto.Sha256(peginContractPrograms) + + address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams) if err != nil { return "", nil } @@ -823,3 +886,120 @@ func (m *Manager) GetPeginControlPrograms(claimScript []byte) (string, []byte) { return address.EncodeAddress(), program } + +func (m *Manager) getPeginContractPrograms(claimScript []byte) ([]byte, error) { + + pubkeys := getNewXpub(consensus.ActiveNetParams.FedpegXPubs, claimScript) + num := len(pubkeys) + fmt.Println(pubkeys) + if num == 0 { + return nil, errors.New("Fedpeg's XPubs is empty") + } + params := "" + unlockParams := "" + checkParams := "[" + + for index := 0; index < num; index++ { + param := fmt.Sprintf("pubkey%d", index+1) + params += param + checkParams += param + if (index + 1) < num { + params += "," + checkParams += "," + } + } + params += ": PublicKey" + checkParams += "],[" + + fmt.Println(params) + signNum := getNumberOfSignaturesRequired(pubkeys) + for index := 0; index < signNum; index++ { + param := fmt.Sprintf("sig%d", index+1) + unlockParams += param + checkParams += param + if index+1 < signNum { + unlockParams += "," + checkParams += "," + } + } + + unlockParams += ": Signature" + checkParams += "]" + + lockWith2of3Keys := fmt.Sprintf(lockWith2of3KeysFmt, params, unlockParams, checkParams) + fmt.Println(lockWith2of3Keys) + r := strings.NewReader(lockWith2of3Keys) + compiled, err := compiler.Compile(r) + if err != nil { + return nil, errors.New("Compile contract failed") + } + + contract := compiled[len(compiled)-1] + + if num < len(contract.Params) { + return nil, errors.New("Compile contract failed") + } + + contractArgs, err := convertArguments(contract, pubkeys) + if err != nil { + fmt.Println("Convert arguments into contract parameters error:", err) + return nil, errors.New("Convert arguments into contract parameters error") + } + + instantProg, err := instantiateContract(contract, contractArgs) + if err != nil { + fmt.Println("Instantiate contract error:", err) + return nil, errors.New("Instantiate contract error") + } + + return instantProg, nil +} + +func getNewXpub(federationRedeemXPub []chainkd.XPub, claimScript []byte) []ed25519.PublicKey { + + var pubkeys []ed25519.PublicKey + for _, xpub := range federationRedeemXPub { + // pub + scriptPubKey 生成一个随机数A + var tmp [32]byte + h := hmac.New(sha256.New, xpub[:]) + h.Write(claimScript) + tweak := h.Sum(tmp[:]) + // pub + A 生成一个新的公钥pub_new + chaildXPub := xpub.Child(tweak) + pubkeys = append(pubkeys, chaildXPub.PublicKey()) + } + return pubkeys +} + +func getNumberOfSignaturesRequired(pubkeys []ed25519.PublicKey) int { + return len(pubkeys)/2 + 1 +} + +// InstantiateContract instantiate contract parameters +func instantiateContract(contract *compiler.Contract, args []compiler.ContractArg) ([]byte, error) { + program, err := compiler.Instantiate(contract.Body, contract.Params, contract.Recursive, args) + if err != nil { + return nil, err + } + + return program, nil +} + +func convertArguments(contract *compiler.Contract, args []ed25519.PublicKey) ([]compiler.ContractArg, error) { + var contractArgs []compiler.ContractArg + for i, p := range contract.Params { + var argument compiler.ContractArg + switch p.Type { + case "PublicKey": + if len(args[i]) != 64 { + return nil, errors.New("mismatch length for Asset/Hash/PublicKey argument") + } + argument.S = (*chainjson.HexBytes)(&args[i]) + default: + return nil, errors.New("Contract parameter type error") + } + contractArgs = append(contractArgs, argument) + } + + return contractArgs, nil +} diff --git a/api/api.go b/api/api.go index 940d6d28..bea80e6a 100644 --- a/api/api.go +++ b/api/api.go @@ -248,6 +248,7 @@ func (a *API) buildHandler() { m.Handle("/recovery-wallet", jsonHandler(a.recoveryFromRootXPubs)) m.Handle("/get-pegin-address", jsonHandler(a.getPeginAddress)) + m.Handle("/get-pegin-contract-address", jsonHandler(a.getAddressForPeginContract)) m.Handle("/claim-pegin-transaction", jsonHandler(a.claimPeginTx)) m.Handle("/create-key-pair", jsonHandler(a.createXKeys)) m.Handle("/get-utxo-from-transaction", jsonHandler(a.getUnspentOutputs)) diff --git a/api/receivers.go b/api/receivers.go index 11408dff..b5da963d 100644 --- a/api/receivers.go +++ b/api/receivers.go @@ -62,3 +62,29 @@ func (a *API) getPeginAddress(ctx context.Context, ins struct { ClaimScript: claimScript, }) } + +func (a *API) getAddressForPeginContract(ctx context.Context, ins struct { + AccountID string `json:"account_id"` + AccountAlias string `json:"account_alias"` +}) Response { + + accountID := ins.AccountID + if ins.AccountAlias != "" { + account, err := a.wallet.AccountMgr.FindByAlias(ins.AccountAlias) + if err != nil { + return NewErrorResponse(err) + } + + accountID = account.ID + } + + mainchainAddress, claimScript, err := a.wallet.AccountMgr.CreatePeginContractAddress(accountID, false) + if err != nil { + return NewErrorResponse(err) + } + + return NewSuccessResponse(fundingResp{ + MainchainAddress: mainchainAddress, + ClaimScript: claimScript, + }) +} diff --git a/node/node.go b/node/node.go index 61c51aee..c3b20526 100644 --- a/node/node.go +++ b/node/node.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "net" "net/http" _ "net/http/pprof" @@ -205,27 +206,30 @@ func initActiveNetParams(config *cfg.Config) { if !exist { cmn.Exit(cmn.Fmt("chain_id[%v] don't exist", config.ChainID)) } - var federationRedeemXPubs []chainkd.XPub - if fedpegXPubs := strings.Split(config.Side.FedpegXPubs, ","); len(fedpegXPubs) > 0 { + if config.Side.FedpegXPubs != "" { + var federationRedeemXPubs []chainkd.XPub + fedpegXPubs := strings.Split(config.Side.FedpegXPubs, ",") for _, xpubStr := range fedpegXPubs { var xpub chainkd.XPub xpub.UnmarshalText([]byte(xpubStr)) federationRedeemXPubs = append(federationRedeemXPubs, xpub) } + consensus.ActiveNetParams.FedpegXPubs = federationRedeemXPubs } - var signBlockXPubs []chainkd.XPub - if xPubs := strings.Split(config.Side.SignBlockXPubs, ","); len(xPubs) > 0 { + if config.Side.SignBlockXPubs != "" { + var signBlockXPubs []chainkd.XPub + fmt.Println(signBlockXPubs) + xPubs := strings.Split(config.Side.SignBlockXPubs, ",") for _, xpubStr := range xPubs { var xpub chainkd.XPub xpub.UnmarshalText([]byte(xpubStr)) signBlockXPubs = append(signBlockXPubs, xpub) } + consensus.ActiveNetParams.SignBlockXPubs = signBlockXPubs } consensus.ActiveNetParams.Signer = config.Signer - consensus.ActiveNetParams.FedpegXPubs = federationRedeemXPubs - consensus.ActiveNetParams.SignBlockXPubs = signBlockXPubs consensus.ActiveNetParams.PeginMinDepth = config.Side.PeginMinDepth consensus.ActiveNetParams.ParentGenesisBlockHash = config.Side.ParentGenesisBlockHash }