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) {
32 spentOutputIDs[*e.SpentOutputId] = true
33 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
34 tx.GasInputIDs = append(tx.GasInputIDs, id)
39 tx.GasInputIDs = append(tx.GasInputIDs, id)
45 if ord >= uint64(len(oldTx.Inputs)) {
51 for id := range spentOutputIDs {
52 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
57 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
58 entryMap = make(map[bc.Hash]bc.Entry)
59 addEntry := func(e bc.Entry) bc.Hash {
67 issuances []*bc.Issuance
71 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
72 for i, input := range tx.Inputs {
73 switch inp := input.TypedInput.(type) {
75 nonceHash := inp.NonceHash()
76 assetDefHash := inp.AssetDefinitionHash()
77 value := input.AssetAmount()
79 issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
80 issuance.WitnessAssetDefinition = &bc.AssetDefinition{
82 IssuanceProgram: &bc.Program{
83 VmVersion: inp.VMVersion,
84 Code: inp.IssuanceProgram,
87 issuance.WitnessArguments = inp.Arguments
88 issuanceID := addEntry(issuance)
90 muxSources[i] = &bc.ValueSource{
94 issuances = append(issuances, issuance)
97 // create entry for prevout
98 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
99 src := &bc.ValueSource{
101 Value: &inp.AssetAmount,
102 Position: inp.SourcePosition,
104 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
105 prevoutID := addEntry(prevout)
106 // create entry for spend
107 spend := bc.NewSpend(&prevoutID, uint64(i))
108 spend.WitnessArguments = inp.Arguments
109 spendID := addEntry(spend)
111 muxSources[i] = &bc.ValueSource{
113 Value: &inp.AssetAmount,
115 spends = append(spends, spend)
118 coinbase = bc.NewCoinbase(inp.Arbitrary)
119 coinbaseID := addEntry(coinbase)
122 value := out.AssetAmount()
123 muxSources[i] = &bc.ValueSource{
130 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
131 muxID := addEntry(mux)
133 // connect the inputs to the mux
134 for _, spend := range spends {
135 spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput)
136 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
138 for _, issuance := range issuances {
139 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
143 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
146 // convert types.outputs to the bc.output
147 var resultIDs []*bc.Hash
148 for i, out := range tx.Outputs {
149 value := out.AssetAmount()
150 src := &bc.ValueSource{
157 // must deal with retirement first due to cases' priorities in the switch statement
158 case vmutil.IsUnspendable(out.ControlProgram()):
160 r := bc.NewRetirement(src, uint64(i))
161 resultID = addEntry(r)
163 case out.OutputType() == IntraChainOutputType:
164 // non-retirement intra-chain tx
165 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
166 o := bc.NewIntraChainOutput(src, prog, uint64(i))
167 resultID = addEntry(o)
169 case out.OutputType() == CrossChainOutputType:
170 // non-retirement cross-chain tx
171 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
172 o := bc.NewCrossChainOutput(src, prog, uint64(i))
173 resultID = addEntry(o)
175 case out.OutputType() == VoteOutputType:
176 // non-retirement vote tx
177 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
178 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
179 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
180 resultID = addEntry(o)
183 log.Warn("unknown outType")
186 dest := &bc.ValueDestination{
191 resultIDs = append(resultIDs, &resultID)
192 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
195 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
196 return addEntry(h), h, entryMap
199 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
200 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
201 return bc.EntryID(bh), bh
204 // MapBlock converts a types block to bc block
205 func MapBlock(old *Block) *bc.Block {
211 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
212 for _, oldTx := range old.Transactions {
213 b.Transactions = append(b.Transactions, oldTx.Tx)