X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=api%2Fmain_transact.go;fp=api%2Fmain_transact.go;h=fdce0b0c1a8210e8a43e26134eeea20c59d2a2c3;hb=f58a184bb6507d0d2bc4962b977de698abace5d6;hp=4bb63c8211aea7ab2753ffeb241b9170a901eae6;hpb=6228102ebf8ffa17faa622662355d7c2dcdc147f;p=bytom%2Fvapor.git diff --git a/api/main_transact.go b/api/main_transact.go index 4bb63c82..fdce0b0c 100644 --- a/api/main_transact.go +++ b/api/main_transact.go @@ -1,328 +1,49 @@ package api import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/vapor/account" - "github.com/vapor/blockchain/txbuilder" - "github.com/vapor/blockchain/txbuilder/mainchain" - "github.com/vapor/common" - "github.com/vapor/consensus" - "github.com/vapor/crypto/ed25519/chainkd" + "github.com/vapor/claim/rpc" + maintx "github.com/vapor/claim/rpc/bytom" chainjson "github.com/vapor/encoding/json" - "github.com/vapor/equity/pegin_contract" - "github.com/vapor/errors" - "github.com/vapor/protocol/bc" - "github.com/vapor/protocol/bc/types" - bytomtypes "github.com/vapor/protocol/bc/types/bytom/types" - "github.com/vapor/protocol/vm/vmutil" ) -func (a *API) buildMainChainTxForContract(ins struct { - Utxo account.UTXO `json:"utxo"` - Tx types.Tx `json:"raw_transaction"` - RootXPubs []chainkd.XPub `json:"root_xpubs"` - ControlProgram string `json:"control_program"` - ClaimScript chainjson.HexBytes `json:"claim_script"` -}) Response { - - var xpubs []chainkd.XPub - for _, xpub := range ins.RootXPubs { - // pub + scriptPubKey 生成一个随机数A - var tmp [32]byte - h := hmac.New(sha256.New, xpub[:]) - h.Write(ins.ClaimScript) - tweak := h.Sum(tmp[:]) - // pub + A 生成一个新的公钥pub_new - chaildXPub := xpub.Child(tweak) - xpubs = append(xpubs, chaildXPub) - } - - txInput, sigInst, err := contractToInputs(a, &ins.Utxo, xpubs, ins.ClaimScript) - builder := mainchain.NewBuilder(time.Now()) - builder.AddInput(txInput, sigInst) - changeAmount := uint64(0) - retire := false - for _, key := range ins.Tx.GetResultIds() { - output, err := ins.Tx.Retire(*key) - if err != nil { - log.WithFields(log.Fields{"moudle": "transact", "err": err}).Warn("buildMainChainTx error") - continue - } - retire = true - var controlProgram []byte - retBool := true - if controlProgram, retBool = getInput(ins.Tx.Entries, *key, ins.ControlProgram); !retBool { - return NewErrorResponse(errors.New("The corresponding input cannot be found")) - } - - assetID := *output.Source.Value.AssetId - out := bytomtypes.NewTxOutput(assetID, output.Source.Value.Amount, controlProgram) - builder.AddOutput(out) - changeAmount = ins.Utxo.Amount - output.Source.Value.Amount - - } - - if !retire { - return NewErrorResponse(errors.New("It's not a transaction to retire assets")) - } - - if changeAmount > 0 { - u := ins.Utxo - out := bytomtypes.NewTxOutput(u.AssetID, changeAmount, ins.Utxo.ControlProgram) - builder.AddOutput(out) - } - - tmpl, tx, err := builder.Build() - if err != nil { - return NewErrorResponse(err) - } - - for i, out := range tmpl.Transaction.Outputs { - if bytes.Equal(out.ControlProgram, ins.Utxo.ControlProgram) { - //tx.Outputs[i].Amount = changeAmount - uint64(txGasResp.TotalNeu) - tx.Outputs[i].Amount = changeAmount - 100000000 - } - } - tmpl.Transaction = bytomtypes.NewTx(*tx) - return NewSuccessResponse(tmpl) +type mainTxResp struct { + Tx chainjson.HexBytes `json:"tx"` } -func (a *API) buildMainChainTx(ins struct { - Utxo account.UTXO `json:"utxo"` - Tx types.Tx `json:"raw_transaction"` - RootXPubs []chainkd.XPub `json:"root_xpubs"` - ControlProgram string `json:"control_program"` - ClaimScript chainjson.HexBytes `json:"claim_script"` -}) Response { - - var xpubs []chainkd.XPub - for _, xpub := range ins.RootXPubs { - // pub + scriptPubKey 生成一个随机数A - var tmp [32]byte - h := hmac.New(sha256.New, xpub[:]) - h.Write(ins.ClaimScript) - tweak := h.Sum(tmp[:]) - // pub + A 生成一个新的公钥pub_new - chaildXPub := xpub.Child(tweak) - xpubs = append(xpubs, chaildXPub) +func (a *API) buildMainChainTxForContract(ins rpc.MainTxParam) Response { + main := &maintx.BytomMainTx{ + MainTxParam: ins, } - txInput, sigInst, err := utxoToInputs(xpubs, &ins.Utxo) - if err != nil { - return NewErrorResponse(err) - } - - builder := mainchain.NewBuilder(time.Now()) - builder.AddInput(txInput, sigInst) - changeAmount := uint64(0) - retire := false - for _, key := range ins.Tx.GetResultIds() { - output, err := ins.Tx.Retire(*key) - if err != nil { - log.WithFields(log.Fields{"moudle": "transact", "err": err}).Warn("buildMainChainTx error") - continue - } - retire = true - var controlProgram []byte - retBool := true - if controlProgram, retBool = getInput(ins.Tx.Entries, *key, ins.ControlProgram); !retBool { - return NewErrorResponse(errors.New("The corresponding input cannot be found")) - } - - assetID := *output.Source.Value.AssetId - out := bytomtypes.NewTxOutput(assetID, output.Source.Value.Amount, controlProgram) - builder.AddOutput(out) - changeAmount = ins.Utxo.Amount - output.Source.Value.Amount - - } - - if !retire { - return NewErrorResponse(errors.New("It's not a transaction to retire assets")) - } - - if changeAmount > 0 { - u := ins.Utxo - out := bytomtypes.NewTxOutput(u.AssetID, changeAmount, ins.Utxo.ControlProgram) - builder.AddOutput(out) - } - - tmpl, tx, err := builder.Build() - if err != nil { - return NewErrorResponse(err) - } - //交易费估算 - txGasResp, err := EstimateTxGasForMainchain(*tmpl) + resp, err := main.BuildMainChainTxForContract() if err != nil { return NewErrorResponse(err) } - for i, out := range tmpl.Transaction.Outputs { - if bytes.Equal(out.ControlProgram, ins.Utxo.ControlProgram) { - tx.Outputs[i].Amount = changeAmount - uint64(txGasResp.TotalNeu) - } - } - tmpl.Transaction = bytomtypes.NewTx(*tx) - return NewSuccessResponse(tmpl) -} - -// -func getInput(entry map[bc.Hash]bc.Entry, outputID bc.Hash, controlProgram string) ([]byte, bool) { - output := entry[outputID].(*bc.Retirement) - mux := entry[*output.Source.Ref].(*bc.Mux) - for _, valueSource := range mux.GetSources() { - spend := entry[*valueSource.Ref].(*bc.Spend) - prevout := entry[*spend.SpentOutputId].(*bc.Output) - - var ctrlProgram chainjson.HexBytes - ctrlProgram = prevout.ControlProgram.Code - tmp, _ := ctrlProgram.MarshalText() - if string(tmp) == controlProgram { - return ctrlProgram, true - } - } - return nil, false + return NewSuccessResponse(&mainTxResp{Tx: resp}) } -// UtxoToInputs convert an utxo to the txinput -func utxoToInputs(xpubs []chainkd.XPub, u *account.UTXO) (*bytomtypes.TxInput, *mainchain.SigningInstruction, error) { - txInput := bytomtypes.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram) - sigInst := &mainchain.SigningInstruction{} - quorum := len(xpubs) - if u.Address == "" { - sigInst.AddWitnessKeys(xpubs, quorum) - return txInput, sigInst, nil +func (a *API) buildMainChainTx(ins rpc.MainTxParam) Response { + main := &maintx.BytomMainTx{ + MainTxParam: ins, } - address, err := common.DecodeBytomAddress(u.Address, &consensus.ActiveNetParams) + resp, err := main.BuildMainChainTx() if err != nil { - return nil, nil, err - } - - sigInst.AddRawWitnessKeysWithoutPath(xpubs, quorum) - - switch address.(type) { - case *common.AddressWitnessPubKeyHash: - derivedPK := xpubs[0].PublicKey() - sigInst.WitnessComponents = append(sigInst.WitnessComponents, mainchain.DataWitness([]byte(derivedPK))) - - case *common.AddressWitnessScriptHash: - derivedXPubs := xpubs - derivedPKs := chainkd.XPubKeys(derivedXPubs) - script, err := vmutil.P2SPMultiSigProgram(derivedPKs, quorum) - if err != nil { - return nil, nil, err - } - sigInst.WitnessComponents = append(sigInst.WitnessComponents, mainchain.DataWitness(script)) - - default: - return nil, nil, errors.New("unsupport address type") + return NewErrorResponse(err) } - return txInput, sigInst, nil + return NewSuccessResponse(&mainTxResp{Tx: resp}) } -func contractToInputs(a *API, u *account.UTXO, xpubs []chainkd.XPub, ClaimScript chainjson.HexBytes) (*bytomtypes.TxInput, *mainchain.SigningInstruction, error) { - txInput := bytomtypes.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram) - sigInst := &mainchain.SigningInstruction{} - - // raw_tx_signature - for _, xpub := range xpubs { - xpubsTmp := []chainkd.XPub{xpub} - sigInst.AddRawWitnessKeysWithoutPath(xpubsTmp, 1) +func (a *API) signWithKey(ins rpc.MainTxSignParam) Response { + sign := maintx.BytomMainSign{ + MainTxSignParam: ins, } - // data - peginContractPrograms, err := pegin_contract.GetPeginContractPrograms(ClaimScript) + resp, err := sign.SignWithKey() if err != nil { - return nil, nil, err - } - sigInst.WitnessComponents = append(sigInst.WitnessComponents, mainchain.DataWitness(peginContractPrograms)) - - return txInput, sigInst, nil -} - -type signRespForMainchain struct { - Tx *mainchain.Template `json:"transaction"` - SignComplete bool `json:"sign_complete"` -} - -func (a *API) signWithKey(ins struct { - Xprv string `json:"xprv"` - XPub chainkd.XPub `json:"xpub"` - Txs mainchain.Template `json:"transaction"` - ClaimScript chainjson.HexBytes `json:"claim_script"` -}) Response { - xprv := &chainkd.XPrv{} - if err := xprv.UnmarshalText([]byte(ins.Xprv)); err != nil { return NewErrorResponse(err) } - // pub + scriptPubKey 生成一个随机数A - var tmp [32]byte - h := hmac.New(sha256.New, ins.XPub[:]) - h.Write(ins.ClaimScript) - tweak := h.Sum(tmp[:]) - // pub + A 生成一个新的公钥pub_new - privateKey := xprv.Child(tweak, false) - - if err := sign(&ins.Txs, privateKey); err != nil { - return NewErrorResponse(err) - } - log.Info("Sign Transaction complete.") - log.Info(mainchain.SignProgress(&ins.Txs)) - return NewSuccessResponse(&signRespForMainchain{Tx: &ins.Txs, SignComplete: mainchain.SignProgress(&ins.Txs)}) -} - -func sign(tmpl *mainchain.Template, xprv chainkd.XPrv) error { - for i, sigInst := range tmpl.SigningInstructions { - for j, wc := range sigInst.WitnessComponents { - switch sw := wc.(type) { - case *mainchain.SignatureWitness: - err := sw.Sign(tmpl, uint32(i), xprv) - if err != nil { - return errors.WithDetailf(err, "adding signature(s) to signature witness component %d of input %d", j, i) - } - case *mainchain.RawTxSigWitness: - err := sw.Sign(tmpl, uint32(i), xprv) - if err != nil { - return errors.WithDetailf(err, "adding signature(s) to raw-signature witness component %d of input %d", j, i) - } - } - } - } - return materializeWitnesses(tmpl) -} - -func materializeWitnesses(txTemplate *mainchain.Template) error { - msg := txTemplate.Transaction - - if msg == nil { - return errors.Wrap(txbuilder.ErrMissingRawTx) - } - - if len(txTemplate.SigningInstructions) > len(msg.Inputs) { - return errors.Wrap(txbuilder.ErrBadInstructionCount) - } - - for i, sigInst := range txTemplate.SigningInstructions { - if msg.Inputs[sigInst.Position] == nil { - return errors.WithDetailf(txbuilder.ErrBadTxInputIdx, "signing instruction %d references missing tx input %d", i, sigInst.Position) - } - - var witness [][]byte - for j, wc := range sigInst.WitnessComponents { - err := wc.Materialize(&witness) - if err != nil { - return errors.WithDetailf(err, "error in witness component %d of input %d", j, i) - } - } - msg.SetInputArguments(sigInst.Position, witness) - } - - return nil + return NewSuccessResponse(resp) }