package validation
import (
- "bytes"
- "encoding/json"
"fmt"
"math"
- "strconv"
+ "github.com/vapor/claim"
"github.com/vapor/consensus"
"github.com/vapor/consensus/segwit"
- "github.com/vapor/crypto"
- "github.com/vapor/equity/pegin_contract"
"github.com/vapor/errors"
"github.com/vapor/math/checked"
"github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types/bytom"
- bytomtypes "github.com/vapor/protocol/bc/types/bytom/types"
"github.com/vapor/protocol/vm"
- "github.com/vapor/protocol/vm/vmutil"
- "github.com/vapor/util"
)
// validate transaction error
case *bc.Mux:
parity := make(map[bc.AssetID]int64)
for i, src := range e.Sources {
+ _, ok := vs.tx.Entries[*src.Ref]
+ if !ok {
+ return errors.Wrapf(bc.ErrMissingEntry, "entry for bytom input %x not found", *src.Ref)
+ }
+
if src.Value.Amount > math.MaxInt64 {
return errors.WithDetailf(ErrOverflow, "amount %d exceeds maximum value 2^63", src.Value.Amount)
}
if !ok {
return errors.Wrapf(bc.ErrMissingEntry, "entry for bytom input %x not found", BTMInputID)
}
-
vs2 := *vs
vs2.entryID = BTMInputID
if err := checkValid(&vs2, e); err != nil {
if err != nil {
return errors.Wrap(err, "getting spend prevout")
}
-
gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft)
if err != nil {
return errors.Wrap(err, "checking control program")
return errors.New("pegin-no-witness")
}
- if err := IsValidPeginWitness(stack, *spentOutput); err != nil {
+ // 根据claim链类型选择验证类型
+ validation := &claim.BytomClaimValidation{}
+ if err := validation.IsValidPeginWitness(stack, *spentOutput); err != nil {
return err
}
- // 判断cliam tx的输入是否已经被用
-
eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value)
if err != nil {
return err
return nil
}
-type MerkleBlock struct {
- BlockHeader []byte `json:"block_header"`
- TxHashes []*bytom.Hash `json:"tx_hashes"`
- StatusHashes []*bytom.Hash `json:"status_hashes"`
- Flags []uint32 `json:"flags"`
- MatchedTxIDs []*bytom.Hash `json:"matched_tx_ids"`
-}
-
-func IsValidPeginWitness(peginWitness [][]byte, prevout bc.Output) (err error) {
- assetID := bytom.AssetID{}
- assetID.V0 = prevout.Source.Value.AssetId.GetV0()
- assetID.V1 = prevout.Source.Value.AssetId.GetV1()
- assetID.V2 = prevout.Source.Value.AssetId.GetV2()
- assetID.V3 = prevout.Source.Value.AssetId.GetV3()
- //bytomPrevout.Source.Value.AssetId = &assetId
-
- sourceID := bytom.Hash{}
- sourceID.V0 = prevout.Source.Ref.GetV0()
- sourceID.V1 = prevout.Source.Ref.GetV1()
- sourceID.V2 = prevout.Source.Ref.GetV2()
- sourceID.V3 = prevout.Source.Ref.GetV3()
-
- assetAmount := &bytom.AssetAmount{
- AssetId: &assetID,
- Amount: prevout.Source.Value.Amount,
- }
-
- src := &bytom.ValueSource{
- Ref: &sourceID,
- Value: assetAmount,
- Position: prevout.Source.Position,
- }
- prog := &bytom.Program{prevout.ControlProgram.VmVersion, prevout.ControlProgram.Code}
- bytomPrevout := bytom.NewOutput(src, prog, prevout.Source.Position)
-
- if len(peginWitness) != 5 {
- return errors.New("peginWitness is error")
- }
- amount, err := strconv.ParseUint(string(peginWitness[0]), 10, 64)
- if err != nil {
- return err
- }
- if !consensus.MoneyRange(amount) {
- return errors.New("Amount out of range")
- }
-
- if len(peginWitness[1]) != 64 {
- return errors.New("The length of gennesisBlockHash is not correct")
- }
-
- claimScript := peginWitness[2]
-
- rawTx := &bytomtypes.Tx{}
- err = rawTx.UnmarshalText(peginWitness[3])
- if err != nil {
- return err
- }
-
- merkleBlock := &MerkleBlock{}
- err = json.Unmarshal(peginWitness[4], merkleBlock)
- if err != nil {
- return err
- }
- // proof验证
- var flags []uint8
- for flag := range merkleBlock.Flags {
- flags = append(flags, uint8(flag))
- }
- blockHeader := &bytomtypes.BlockHeader{}
- if err = blockHeader.UnmarshalText(merkleBlock.BlockHeader); err != nil {
- return err
- }
-
- if !bytomtypes.ValidateTxMerkleTreeProof(merkleBlock.TxHashes, flags, merkleBlock.MatchedTxIDs, blockHeader.BlockCommitment.TransactionsMerkleRoot) {
- return errors.New("Merkleblock validation failed")
- }
-
- // 交易进行验证
- if err = checkPeginTx(rawTx, bytomPrevout, amount, claimScript); err != nil {
- return err
- }
-
- // Check the genesis block corresponds to a valid peg (only one for now)
- if !bytes.Equal(peginWitness[1], []byte(consensus.ActiveNetParams.ParentGenesisBlockHash)) {
- return errors.New("ParentGenesisBlockHash don't match")
- }
- // TODO Finally, validate peg-in via rpc call
-
- if util.ValidatePegin {
- if err := util.IsConfirmedBytomBlock(blockHeader.Height, consensus.ActiveNetParams.PeginMinDepth); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func checkPeginTx(rawTx *bytomtypes.Tx, prevout *bytom.Output, claimAmount uint64, claimScript []byte) error {
- // Check the transaction nout/value matches
- amount := rawTx.Outputs[prevout.Source.Position].Amount
- if claimAmount != amount {
- return errors.New("transaction nout/value do not matches")
- }
- // Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
- //federationRedeemScript := vmutil.CalculateContract(consensus.ActiveNetParams.FedpegXPubs, claimScript)
- //scriptHash := crypto.Sha256(federationRedeemScript)
- peginContractPrograms, err := pegin_contract.GetPeginContractPrograms(claimScript)
- if err != nil {
- return err
- }
-
- scriptHash := crypto.Sha256(peginContractPrograms)
- controlProg, err := vmutil.P2WSHProgram(scriptHash)
- if err != nil {
- return err
- }
- if !bytes.Equal(rawTx.Outputs[prevout.Source.Position].ControlProgram, controlProg) {
- return errors.New("The output control program of transaction does not match the control program of the system's alliance contract")
- }
- return nil
-}
-
func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error {
if vs == nil {
return errors.Wrap(ErrMissingField, "empty value source")