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 for id, e := range entries {
26 switch e := e.(type) {
27 case *bc.CrossChainInput:
29 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
30 tx.GasInputIDs = append(tx.GasInputIDs, id)
35 spentOutputIDs[*e.SpentOutputId] = true
36 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
37 tx.GasInputIDs = append(tx.GasInputIDs, id)
42 tx.GasInputIDs = append(tx.GasInputIDs, id)
48 if ord >= uint64(len(oldTx.Inputs)) {
54 for id := range spentOutputIDs {
55 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
60 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
61 entryMap = make(map[bc.Hash]bc.Entry)
62 addEntry := func(e bc.Entry) bc.Hash {
70 crossIns []*bc.CrossChainInput
74 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
75 for i, input := range tx.Inputs {
76 switch inp := input.TypedInput.(type) {
78 // create entry for prevout
79 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
80 src := &bc.ValueSource{
82 Value: &inp.AssetAmount,
83 Position: inp.SourcePosition,
85 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
86 prevoutID := addEntry(prevout)
87 // create entry for spend
88 spend := bc.NewSpend(&prevoutID, uint64(i))
89 spend.WitnessArguments = inp.Arguments
90 spendID := addEntry(spend)
92 muxSources[i] = &bc.ValueSource{
94 Value: &inp.AssetAmount,
96 spends = append(spends, spend)
99 coinbase = bc.NewCoinbase(inp.Arbitrary)
100 coinbaseID := addEntry(coinbase)
103 value := out.AssetAmount()
104 muxSources[i] = &bc.ValueSource{
110 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
111 src := &bc.ValueSource{
113 Value: &inp.AssetAmount,
114 Position: inp.SourcePosition,
116 prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs
117 prevoutID := addEntry(prevout)
118 // create entry for spend
119 spend := bc.NewSpend(&prevoutID, uint64(i))
120 spend.WitnessArguments = inp.Arguments
121 spendID := addEntry(spend)
123 muxSources[i] = &bc.ValueSource{
125 Value: &inp.AssetAmount,
127 spends = append(spends, spend)
129 case *CrossChainInput:
130 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
131 src := &bc.ValueSource{
133 Value: &inp.AssetAmount,
134 Position: inp.SourcePosition,
136 prevout := bc.NewCrossChainOutput(src, prog, 0) // ordinal doesn't matter
137 outputID := bc.EntryID(prevout)
138 crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, uint64(i))
139 crossIn.WitnessArguments = inp.Arguments
140 crossInID := addEntry(crossIn)
141 muxSources[i] = &bc.ValueSource{
143 Value: &inp.AssetAmount,
145 crossIns = append(crossIns, crossIn)
150 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
151 muxID := addEntry(mux)
153 // connect the inputs to the mux
154 for _, spend := range spends {
155 spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput)
156 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
159 for _, crossIn := range crossIns {
160 crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal)
164 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
167 // convert types.outputs to the bc.output
168 var resultIDs []*bc.Hash
169 for i, out := range tx.Outputs {
170 value := out.AssetAmount()
171 src := &bc.ValueSource{
178 // must deal with retirement first due to cases' priorities in the switch statement
179 case vmutil.IsUnspendable(out.ControlProgram()):
181 r := bc.NewRetirement(src, uint64(i))
182 resultID = addEntry(r)
184 case out.OutputType() == IntraChainOutputType:
185 // non-retirement intra-chain tx
186 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
187 o := bc.NewIntraChainOutput(src, prog, uint64(i))
188 resultID = addEntry(o)
190 case out.OutputType() == CrossChainOutputType:
191 // non-retirement cross-chain tx
192 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
193 o := bc.NewCrossChainOutput(src, prog, uint64(i))
194 resultID = addEntry(o)
196 case out.OutputType() == VoteOutputType:
197 // non-retirement vote tx
198 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
199 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
200 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
201 resultID = addEntry(o)
204 log.Warn("unknown outType")
207 dest := &bc.ValueDestination{
212 resultIDs = append(resultIDs, &resultID)
213 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
216 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
217 return addEntry(h), h, entryMap
220 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
221 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
222 return bc.EntryID(bh), bh
225 // MapBlock converts a types block to bc block
226 func MapBlock(old *Block) *bc.Block {
232 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
233 for _, oldTx := range old.Transactions {
234 b.Transactions = append(b.Transactions, oldTx.Tx)