4 log "github.com/sirupsen/logrus"
5 "golang.org/x/crypto/sha3"
7 "github.com/vapor/consensus"
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 mainchainOutputIDs := make(map[bc.Hash]bool)
26 for id, e := range entries {
28 switch e := e.(type) {
29 case *bc.CrossChainInput:
31 mainchainOutputIDs[*e.MainchainOutputId] = true
32 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
33 tx.GasInputIDs = append(tx.GasInputIDs, id)
38 spentOutputIDs[*e.SpentOutputId] = true
39 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
40 tx.GasInputIDs = append(tx.GasInputIDs, id)
45 spentOutputIDs[*e.SpentOutputId] = true
46 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
47 tx.GasInputIDs = append(tx.GasInputIDs, id)
52 tx.GasInputIDs = append(tx.GasInputIDs, id)
58 if ord >= uint64(len(oldTx.Inputs)) {
64 for id := range spentOutputIDs {
65 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
67 for id := range mainchainOutputIDs {
68 tx.MainchainOutputIDs = append(tx.MainchainOutputIDs, id)
73 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
74 entryMap = make(map[bc.Hash]bc.Entry)
75 addEntry := func(e bc.Entry) bc.Hash {
83 vetoInputs []*bc.VetoInput
84 crossIns []*bc.CrossChainInput
88 muxSources := make([]*bc.ValueSource, len(tx.Inputs))
89 for i, input := range tx.Inputs {
90 switch inp := input.TypedInput.(type) {
92 // create entry for prevout
93 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
94 src := &bc.ValueSource{
96 Value: &inp.AssetAmount,
97 Position: inp.SourcePosition,
99 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
100 prevoutID := addEntry(prevout)
101 // create entry for spend
102 spend := bc.NewSpend(&prevoutID, uint64(i))
103 spend.WitnessArguments = inp.Arguments
104 spendID := addEntry(spend)
106 muxSources[i] = &bc.ValueSource{
108 Value: &inp.AssetAmount,
110 spends = append(spends, spend)
113 coinbase = bc.NewCoinbase(inp.Arbitrary)
114 coinbaseID := addEntry(coinbase)
117 value := out.AssetAmount()
118 muxSources[i] = &bc.ValueSource{
124 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
125 src := &bc.ValueSource{
127 Value: &inp.AssetAmount,
128 Position: inp.SourcePosition,
130 prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs
131 prevoutID := addEntry(prevout)
132 // create entry for VetoInput
133 vetoInput := bc.NewVetoInput(&prevoutID, uint64(i))
134 vetoInput.WitnessArguments = inp.Arguments
135 vetoVoteID := addEntry(vetoInput)
137 muxSources[i] = &bc.ValueSource{
139 Value: &inp.AssetAmount,
141 vetoInputs = append(vetoInputs, vetoInput)
143 case *CrossChainInput:
144 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
145 src := &bc.ValueSource{
147 Value: &inp.AssetAmount,
148 Position: inp.SourcePosition,
151 prevout := bc.NewIntraChainOutput(src, prog, 0) // ordinal doesn't matter
152 outputID := bc.EntryID(prevout)
154 assetDefHash := bc.NewHash(sha3.Sum256(inp.AssetDefinition))
155 assetDef := &bc.AssetDefinition{
157 IssuanceProgram: &bc.Program{
158 VmVersion: inp.VMVersion,
159 Code: inp.IssuanceProgram,
163 crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, prog, uint64(i), assetDef)
164 crossIn.WitnessArguments = inp.Arguments
165 crossInID := addEntry(crossIn)
166 muxSources[i] = &bc.ValueSource{
168 Value: &inp.AssetAmount,
170 crossIns = append(crossIns, crossIn)
174 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
175 muxID := addEntry(mux)
177 // connect the inputs to the mux
178 for _, spend := range spends {
179 spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput)
180 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
183 for _, vetoInput := range vetoInputs {
184 voteOutput := entryMap[*vetoInput.SpentOutputId].(*bc.VoteOutput)
185 vetoInput.SetDestination(&muxID, voteOutput.Source.Value, vetoInput.Ordinal)
188 for _, crossIn := range crossIns {
189 crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal)
193 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
196 // convert types.outputs to the bc.output
197 var resultIDs []*bc.Hash
198 for i, out := range tx.Outputs {
199 value := out.AssetAmount()
200 src := &bc.ValueSource{
207 // must deal with retirement first due to cases' priorities in the switch statement
208 case vmutil.IsUnspendable(out.ControlProgram()):
210 r := bc.NewRetirement(src, uint64(i))
211 resultID = addEntry(r)
213 case out.OutputType() == IntraChainOutputType:
214 // non-retirement intra-chain tx
215 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
216 o := bc.NewIntraChainOutput(src, prog, uint64(i))
217 resultID = addEntry(o)
219 case out.OutputType() == CrossChainOutputType:
220 // non-retirement cross-chain tx
221 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
222 o := bc.NewCrossChainOutput(src, prog, uint64(i))
223 resultID = addEntry(o)
225 case out.OutputType() == VoteOutputType:
226 // non-retirement vote tx
227 voteOut, _ := out.TypedOutput.(*VoteTxOutput)
228 prog := &bc.Program{out.VMVersion(), out.ControlProgram()}
229 o := bc.NewVoteOutput(src, prog, uint64(i), voteOut.Vote)
230 resultID = addEntry(o)
233 log.Warn("unknown outType")
236 dest := &bc.ValueDestination{
241 resultIDs = append(resultIDs, &resultID)
242 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
245 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
246 return addEntry(h), h, entryMap
249 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
250 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Witness)
251 return bc.EntryID(bh), bh
254 // MapBlock converts a types block to bc block
255 func MapBlock(old *Block) *bc.Block {
261 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
262 for _, oldTx := range old.Transactions {
263 b.Transactions = append(b.Transactions, oldTx.Tx)