4 log "github.com/sirupsen/logrus"
6 "github.com/vapor/consensus"
7 "github.com/vapor/consensus/federation"
8 "github.com/vapor/protocol/bc"
9 "github.com/vapor/protocol/vm"
10 "github.com/vapor/protocol/vm/vmutil"
13 // MapTx converts a types TxData object into its entries-based
15 func MapTx(oldTx *TxData) *bc.Tx {
16 txID, txHeader, entries := mapTx(oldTx)
21 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
24 spentOutputIDs := make(map[bc.Hash]bool)
25 for id, e := range entries {
27 switch e := e.(type) {
28 case *bc.CrossChainInput:
30 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
31 tx.GasInputIDs = append(tx.GasInputIDs, id)
36 spentOutputIDs[*e.SpentOutputId] = true
37 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
38 tx.GasInputIDs = append(tx.GasInputIDs, id)
43 tx.GasInputIDs = append(tx.GasInputIDs, id)
49 if ord >= uint64(len(oldTx.Inputs)) {
55 for id := range spentOutputIDs {
56 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
61 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
62 entryMap = make(map[bc.Hash]bc.Entry)
63 addEntry := func(e bc.Entry) bc.Hash {
71 crossIns []*bc.CrossChainInput
75 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
76 for i, input := range tx.Inputs {
77 switch inp := input.TypedInput.(type) {
79 // create entry for prevout
80 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
81 src := &bc.ValueSource{
83 Value: &inp.AssetAmount,
84 Position: inp.SourcePosition,
86 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
87 prevoutID := addEntry(prevout)
88 // create entry for spend
89 spend := bc.NewSpend(&prevoutID, uint64(i))
90 spend.WitnessArguments = inp.Arguments
91 spendID := addEntry(spend)
93 muxSources[i] = &bc.ValueSource{
95 Value: &inp.AssetAmount,
97 spends = append(spends, spend)
100 coinbase = bc.NewCoinbase(inp.Arbitrary)
101 coinbaseID := addEntry(coinbase)
104 value := out.AssetAmount()
105 muxSources[i] = &bc.ValueSource{
111 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
112 src := &bc.ValueSource{
114 Value: &inp.AssetAmount,
115 Position: inp.SourcePosition,
117 prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs
118 prevoutID := addEntry(prevout)
119 // create entry for spend
120 spend := bc.NewSpend(&prevoutID, uint64(i))
121 spend.WitnessArguments = inp.Arguments
122 spendID := addEntry(spend)
124 muxSources[i] = &bc.ValueSource{
126 Value: &inp.AssetAmount,
128 spends = append(spends, spend)
130 case *CrossChainInput:
131 // hard code peg-in control program in consensus level, may need to
132 // deal with soft fork (federation members change) in the future
133 prog := &bc.Program{VmVersion: inp.VMVersion, Code: federation.GetFederation().ControlProgram}
134 src := &bc.ValueSource{
136 Value: &inp.AssetAmount,
137 Position: inp.SourcePosition,
139 prevout := bc.NewCrossChainOutput(src, prog, 0) // ordinal doesn't matter
140 outputID := bc.EntryID(prevout)
141 crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, uint64(i))
142 crossIn.WitnessArguments = inp.Arguments
143 crossInID := addEntry(crossIn)
144 muxSources[i] = &bc.ValueSource{
146 Value: &inp.AssetAmount,
148 crossIns = append(crossIns, crossIn)
153 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
154 muxID := addEntry(mux)
156 // connect the inputs to the mux
157 for _, spend := range spends {
158 switch spentOutput := entryMap[*spend.SpentOutputId].(type) {
159 case *bc.IntraChainOutput:
160 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
163 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
167 for _, crossIn := range crossIns {
168 crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal)
172 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
175 // convert types.outputs to the bc.output
176 var resultIDs []*bc.Hash
177 for i, out := range tx.Outputs {
178 value := out.AssetAmount()
179 src := &bc.ValueSource{
186 // must deal with retirement first due to cases' priorities in the switch statement
187 case vmutil.IsUnspendable(out.ControlProgram()):
189 r := bc.NewRetirement(src, uint64(i))
190 resultID = addEntry(r)
192 case out.OutputType() == IntraChainOutputType:
193 // non-retirement intra-chain tx
194 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
195 o := bc.NewIntraChainOutput(src, prog, uint64(i))
196 resultID = addEntry(o)
198 case out.OutputType() == CrossChainOutputType:
199 // non-retirement cross-chain tx
200 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
201 o := bc.NewCrossChainOutput(src, prog, uint64(i))
202 resultID = addEntry(o)
204 case out.OutputType() == VoteOutputType:
205 // non-retirement vote tx
206 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
207 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
208 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
209 resultID = addEntry(o)
212 log.Warn("unknown outType")
215 dest := &bc.ValueDestination{
220 resultIDs = append(resultIDs, &resultID)
221 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
224 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
225 return addEntry(h), h, entryMap
228 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
229 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
230 return bc.EntryID(bh), bh
233 // MapBlock converts a types block to bc block
234 func MapBlock(old *Block) *bc.Block {
240 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
241 for _, oldTx := range old.Transactions {
242 b.Transactions = append(b.Transactions, oldTx.Tx)