OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / claim / bytom_validation.go
1 package claim
2
3 import (
4         "bytes"
5         "encoding/json"
6         "strconv"
7
8         bytomtypes "github.com/vapor/claim/bytom/protocolbc/types"
9         "github.com/vapor/consensus"
10         "github.com/vapor/crypto"
11         "github.com/vapor/equity/pegin_contract"
12         "github.com/vapor/errors"
13         "github.com/vapor/protocol/bc"
14         "github.com/vapor/protocol/bc/types"
15         "github.com/vapor/protocol/vm/vmutil"
16         "github.com/vapor/util"
17 )
18
19 type MerkleBlock struct {
20         BlockHeader  []byte     `json:"block_header"`
21         TxHashes     []*bc.Hash `json:"tx_hashes"`
22         StatusHashes []*bc.Hash `json:"status_hashes"`
23         Flags        []uint32   `json:"flags"`
24         MatchedTxIDs []*bc.Hash `json:"matched_tx_ids"`
25 }
26
27 type BytomClaimValidation struct {
28 }
29
30 func (b *BytomClaimValidation) IsValidPeginWitness(peginWitness [][]byte, prevout bc.Output) (err error) {
31
32         assetAmount := &bc.AssetAmount{
33                 AssetId: prevout.Source.Value.AssetId,
34                 Amount:  prevout.Source.Value.Amount,
35         }
36
37         src := &bc.ValueSource{
38                 Ref:      prevout.Source.Ref,
39                 Value:    assetAmount,
40                 Position: prevout.Source.Position,
41         }
42         prog := &bc.Program{prevout.ControlProgram.VmVersion, prevout.ControlProgram.Code}
43         bytomPrevout := bc.NewOutput(src, prog, prevout.Source.Position)
44
45         if len(peginWitness) != 5 {
46                 return errors.New("peginWitness is error")
47         }
48         amount, err := strconv.ParseUint(string(peginWitness[0]), 10, 64)
49         if err != nil {
50                 return err
51         }
52         if !consensus.MoneyRange(amount) {
53                 return errors.New("Amount out of range")
54         }
55         /*
56                 if len(peginWitness[1]) != 32 {
57                         return errors.New("The length of gennesisBlockHash is not correct")
58                 }
59         */
60         claimScript := peginWitness[2]
61
62         rawTx := &bytomtypes.Tx{}
63         err = rawTx.UnmarshalText(peginWitness[3])
64         if err != nil {
65                 return err
66         }
67
68         merkleBlock := &MerkleBlock{}
69         err = json.Unmarshal(peginWitness[4], merkleBlock)
70         if err != nil {
71                 return err
72         }
73         // proof验证
74         var flags []uint8
75         for flag := range merkleBlock.Flags {
76                 flags = append(flags, uint8(flag))
77         }
78         blockHeader := &bytomtypes.BlockHeader{}
79         if err = blockHeader.UnmarshalText(merkleBlock.BlockHeader); err != nil {
80                 return err
81         }
82
83         if !types.ValidateTxMerkleTreeProof(merkleBlock.TxHashes, flags, merkleBlock.MatchedTxIDs, blockHeader.BlockCommitment.TransactionsMerkleRoot) {
84                 return errors.New("Merkleblock validation failed")
85         }
86
87         // 交易进行验证
88         if err = b.checkPeginTx(rawTx, bytomPrevout, amount, claimScript); err != nil {
89                 return err
90         }
91         var hash bc.Hash
92         hash.UnmarshalText(peginWitness[1])
93         // Check the genesis block corresponds to a valid peg (only one for now)
94         if hash.String() != consensus.ActiveNetParams.ParentGenesisBlockHash {
95                 return errors.New("ParentGenesisBlockHash don't match")
96         }
97         // TODO Finally, validate peg-in via rpc call
98
99         if util.ValidatePegin {
100                 if err := util.IsConfirmedBytomBlock(blockHeader.Height, consensus.ActiveNetParams.PeginMinDepth); err != nil {
101                         return err
102                 }
103         }
104
105         return nil
106 }
107
108 func (b *BytomClaimValidation) checkPeginTx(rawTx *bytomtypes.Tx, prevout *bc.Output, claimAmount uint64, claimScript []byte) error {
109         // Check the transaction nout/value matches
110         amount := rawTx.Outputs[prevout.Source.Position].Amount
111         if claimAmount != amount {
112                 return errors.New("transaction nout/value do not matches")
113         }
114         // Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
115         //federationRedeemScript := vmutil.CalculateContract(consensus.ActiveNetParams.FedpegXPubs, claimScript)
116         //scriptHash := crypto.Sha256(federationRedeemScript)
117         peginContractPrograms, err := pegin_contract.GetPeginContractPrograms(claimScript)
118         if err != nil {
119                 return err
120         }
121
122         scriptHash := crypto.Sha256(peginContractPrograms)
123         controlProg, err := vmutil.P2WSHProgram(scriptHash)
124         if err != nil {
125                 return err
126         }
127         if !bytes.Equal(rawTx.Outputs[prevout.Source.Position].ControlProgram, controlProg) {
128                 return errors.New("The output control program of transaction does not match the control program of the system's alliance contract")
129         }
130         return nil
131 }