4 log "github.com/sirupsen/logrus"
6 "github.com/vapor/consensus"
7 "github.com/vapor/protocol/bc"
8 "github.com/vapor/protocol/vm"
9 "github.com/vapor/protocol/vm/vmutil"
12 // MapTx converts a types TxData object into its entries-based
14 func MapTx(oldTx *TxData) *bc.Tx {
15 txID, txHeader, entries := mapTx(oldTx)
20 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
23 spentOutputIDs := make(map[bc.Hash]bool)
24 mainchainOutputIDs := make(map[bc.Hash]bool)
25 for id, e := range entries {
27 switch e := e.(type) {
28 case *bc.CrossChainInput:
30 mainchainOutputIDs[*e.MainchainOutputId] = true
31 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
32 tx.GasInputIDs = append(tx.GasInputIDs, id)
37 spentOutputIDs[*e.SpentOutputId] = true
38 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
39 tx.GasInputIDs = append(tx.GasInputIDs, id)
44 tx.GasInputIDs = append(tx.GasInputIDs, id)
50 if ord >= uint64(len(oldTx.Inputs)) {
56 for id := range spentOutputIDs {
57 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
59 for id := range mainchainOutputIDs {
60 tx.MainchainOutputIDs = append(tx.MainchainOutputIDs, id)
65 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
66 entryMap = make(map[bc.Hash]bc.Entry)
67 addEntry := func(e bc.Entry) bc.Hash {
75 crossIns []*bc.CrossChainInput
79 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
80 for i, input := range tx.Inputs {
81 switch inp := input.TypedInput.(type) {
83 // create entry for prevout
84 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
85 src := &bc.ValueSource{
87 Value: &inp.AssetAmount,
88 Position: inp.SourcePosition,
90 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
91 prevoutID := addEntry(prevout)
92 // create entry for spend
93 spend := bc.NewSpend(&prevoutID, uint64(i))
94 spend.WitnessArguments = inp.Arguments
95 spendID := addEntry(spend)
97 muxSources[i] = &bc.ValueSource{
99 Value: &inp.AssetAmount,
101 spends = append(spends, spend)
104 coinbase = bc.NewCoinbase(inp.Arbitrary)
105 coinbaseID := addEntry(coinbase)
108 value := out.AssetAmount()
109 muxSources[i] = &bc.ValueSource{
115 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
116 src := &bc.ValueSource{
118 Value: &inp.AssetAmount,
119 Position: inp.SourcePosition,
121 prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs
122 prevoutID := addEntry(prevout)
123 // create entry for spend
124 spend := bc.NewSpend(&prevoutID, uint64(i))
125 spend.WitnessArguments = inp.Arguments
126 spendID := addEntry(spend)
128 muxSources[i] = &bc.ValueSource{
130 Value: &inp.AssetAmount,
132 spends = append(spends, spend)
134 case *CrossChainInput:
135 // TODO: fed peg script
136 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
137 src := &bc.ValueSource{
139 Value: &inp.AssetAmount,
140 Position: inp.SourcePosition,
142 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter
143 outputID := bc.EntryID(prevout)
144 crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, prog, uint64(i))
145 crossIn.WitnessArguments = inp.Arguments
146 crossInID := addEntry(crossIn)
147 muxSources[i] = &bc.ValueSource{
149 Value: &inp.AssetAmount,
151 crossIns = append(crossIns, crossIn)
155 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
156 muxID := addEntry(mux)
158 // connect the inputs to the mux
159 for _, spend := range spends {
160 switch spentOutput := entryMap[*spend.SpentOutputId].(type) {
161 case *bc.IntraChainOutput:
162 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
165 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
169 for _, crossIn := range crossIns {
170 crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal)
174 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
177 // convert types.outputs to the bc.output
178 var resultIDs []*bc.Hash
179 for i, out := range tx.Outputs {
180 value := out.AssetAmount()
181 src := &bc.ValueSource{
188 // must deal with retirement first due to cases' priorities in the switch statement
189 case vmutil.IsUnspendable(out.ControlProgram()):
191 r := bc.NewRetirement(src, uint64(i))
192 resultID = addEntry(r)
194 case out.OutputType() == IntraChainOutputType:
195 // non-retirement intra-chain tx
196 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
197 o := bc.NewIntraChainOutput(src, prog, uint64(i))
198 resultID = addEntry(o)
200 case out.OutputType() == CrossChainOutputType:
201 // non-retirement cross-chain tx
202 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
203 o := bc.NewCrossChainOutput(src, prog, uint64(i))
204 resultID = addEntry(o)
206 case out.OutputType() == VoteOutputType:
207 // non-retirement vote tx
208 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
209 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
210 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
211 resultID = addEntry(o)
214 log.Warn("unknown outType")
217 dest := &bc.ValueDestination{
222 resultIDs = append(resultIDs, &resultID)
223 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
226 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
227 return addEntry(h), h, entryMap
230 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
231 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
232 return bc.EntryID(bh), bh
235 // MapBlock converts a types block to bc block
236 func MapBlock(old *Block) *bc.Block {
242 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
243 for _, oldTx := range old.Transactions {
244 b.Transactions = append(b.Transactions, oldTx.Tx)