6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/consensus"
9 "github.com/vapor/protocol/bc"
10 "github.com/vapor/protocol/vm"
11 "github.com/vapor/protocol/vm/vmutil"
14 // MapTx converts a types TxData object into its entries-based
16 func MapTx(oldTx *TxData) *bc.Tx {
17 fmt.Println("MapTx start...")
18 txID, txHeader, entries := mapTx(oldTx)
23 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
26 spentOutputIDs := make(map[bc.Hash]bool)
27 mainchainOutputIDs := make(map[bc.Hash]bool)
28 for id, e := range entries {
30 switch e := e.(type) {
31 case *bc.CrossChainInput:
33 mainchainOutputIDs[*e.MainchainOutputId] = true
34 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
35 tx.GasInputIDs = append(tx.GasInputIDs, id)
40 spentOutputIDs[*e.SpentOutputId] = true
41 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
42 tx.GasInputIDs = append(tx.GasInputIDs, id)
47 tx.GasInputIDs = append(tx.GasInputIDs, id)
53 if ord >= uint64(len(oldTx.Inputs)) {
59 for id := range spentOutputIDs {
60 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
62 for id := range mainchainOutputIDs {
63 tx.MainchainOutputIDs = append(tx.MainchainOutputIDs, id)
68 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
69 entryMap = make(map[bc.Hash]bc.Entry)
70 addEntry := func(e bc.Entry) bc.Hash {
78 crossIns []*bc.CrossChainInput
82 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
83 for i, input := range tx.Inputs {
84 switch inp := input.TypedInput.(type) {
86 // create entry for prevout
87 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
88 src := &bc.ValueSource{
90 Value: &inp.AssetAmount,
91 Position: inp.SourcePosition,
93 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
94 prevoutID := addEntry(prevout)
95 // create entry for spend
96 spend := bc.NewSpend(&prevoutID, uint64(i))
97 spend.WitnessArguments = inp.Arguments
98 spendID := addEntry(spend)
100 muxSources[i] = &bc.ValueSource{
102 Value: &inp.AssetAmount,
104 spends = append(spends, spend)
107 coinbase = bc.NewCoinbase(inp.Arbitrary)
108 coinbaseID := addEntry(coinbase)
111 value := out.AssetAmount()
112 muxSources[i] = &bc.ValueSource{
118 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
119 src := &bc.ValueSource{
121 Value: &inp.AssetAmount,
122 Position: inp.SourcePosition,
124 prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs
125 prevoutID := addEntry(prevout)
126 // create entry for spend
127 spend := bc.NewSpend(&prevoutID, uint64(i))
128 spend.WitnessArguments = inp.Arguments
129 spendID := addEntry(spend)
131 muxSources[i] = &bc.ValueSource{
133 Value: &inp.AssetAmount,
135 spends = append(spends, spend)
137 case *CrossChainInput:
138 // TODO: fed peg script
139 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
140 src := &bc.ValueSource{
142 Value: &inp.AssetAmount,
143 Position: inp.SourcePosition,
145 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter
146 outputID := bc.EntryID(prevout)
147 crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, prog, uint64(i))
148 crossIn.WitnessArguments = inp.Arguments
149 crossInID := addEntry(crossIn)
150 muxSources[i] = &bc.ValueSource{
152 Value: &inp.AssetAmount,
154 crossIns = append(crossIns, crossIn)
158 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
159 muxID := addEntry(mux)
161 // connect the inputs to the mux
162 for _, spend := range spends {
163 switch spentOutput := entryMap[*spend.SpentOutputId].(type) {
164 case *bc.IntraChainOutput:
165 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
168 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
172 for _, crossIn := range crossIns {
173 crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal)
177 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
180 // convert types.outputs to the bc.output
181 var resultIDs []*bc.Hash
182 for i, out := range tx.Outputs {
183 value := out.AssetAmount()
184 src := &bc.ValueSource{
191 // must deal with retirement first due to cases' priorities in the switch statement
192 case vmutil.IsUnspendable(out.ControlProgram()):
194 r := bc.NewRetirement(src, uint64(i))
195 resultID = addEntry(r)
197 case out.OutputType() == IntraChainOutputType:
198 // non-retirement intra-chain tx
199 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
200 o := bc.NewIntraChainOutput(src, prog, uint64(i))
201 resultID = addEntry(o)
203 case out.OutputType() == CrossChainOutputType:
204 // non-retirement cross-chain tx
205 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
206 o := bc.NewCrossChainOutput(src, prog, uint64(i))
207 resultID = addEntry(o)
209 case out.OutputType() == VoteOutputType:
210 // non-retirement vote tx
211 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
212 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
213 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
214 resultID = addEntry(o)
217 log.Warn("unknown outType")
220 dest := &bc.ValueDestination{
225 resultIDs = append(resultIDs, &resultID)
226 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
229 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
230 return addEntry(h), h, entryMap
233 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
234 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
235 return bc.EntryID(bh), bh
238 // MapBlock converts a types block to bc block
239 func MapBlock(old *Block) *bc.Block {
245 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
246 for _, oldTx := range old.Transactions {
247 b.Transactions = append(b.Transactions, oldTx.Tx)