github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/bc/types/map.go (about) 1 package types 2 3 import ( 4 "github.com/bytom/bytom/consensus" 5 "github.com/bytom/bytom/protocol/bc" 6 "github.com/bytom/bytom/protocol/vm" 7 "github.com/bytom/bytom/protocol/vm/vmutil" 8 ) 9 10 // MapTx converts a types TxData object into its entries-based 11 // representation. 12 func MapTx(oldTx *TxData) *bc.Tx { 13 txID, txHeader, entries := mapTx(oldTx) 14 tx := &bc.Tx{ 15 TxHeader: txHeader, 16 ID: txID, 17 Entries: entries, 18 InputIDs: make([]bc.Hash, len(oldTx.Inputs)), 19 } 20 21 spentOutputIDs := make(map[bc.Hash]bool) 22 for id, e := range entries { 23 var ord uint64 24 switch e := e.(type) { 25 case *bc.Issuance: 26 ord = e.Ordinal 27 28 case *bc.Spend: 29 ord = e.Ordinal 30 spentOutputIDs[*e.SpentOutputId] = true 31 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID { 32 tx.GasInputIDs = append(tx.GasInputIDs, id) 33 } 34 35 case *bc.Coinbase: 36 ord = 0 37 tx.GasInputIDs = append(tx.GasInputIDs, id) 38 39 default: 40 continue 41 } 42 43 if ord >= uint64(len(oldTx.Inputs)) { 44 continue 45 } 46 tx.InputIDs[ord] = id 47 } 48 49 for id := range spentOutputIDs { 50 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id) 51 } 52 return tx 53 } 54 55 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) { 56 entryMap = make(map[bc.Hash]bc.Entry) 57 addEntry := func(e bc.Entry) bc.Hash { 58 id := bc.EntryID(e) 59 entryMap[id] = e 60 return id 61 } 62 63 var ( 64 spends []*bc.Spend 65 issuances []*bc.Issuance 66 coinbase *bc.Coinbase 67 ) 68 69 muxSources := make([]*bc.ValueSource, len(tx.Inputs)) 70 for i, input := range tx.Inputs { 71 switch inp := input.TypedInput.(type) { 72 case *IssuanceInput: 73 nonceHash := inp.NonceHash() 74 assetDefHash := inp.AssetDefinitionHash() 75 value := input.AssetAmount() 76 77 issuance := bc.NewIssuance(&nonceHash, &value, uint64(i)) 78 issuance.WitnessAssetDefinition = &bc.AssetDefinition{ 79 Data: &assetDefHash, 80 IssuanceProgram: &bc.Program{ 81 VmVersion: inp.VMVersion, 82 Code: inp.IssuanceProgram, 83 }, 84 } 85 issuance.WitnessArguments = inp.Arguments 86 issuanceID := addEntry(issuance) 87 88 muxSources[i] = &bc.ValueSource{ 89 Ref: &issuanceID, 90 Value: &value, 91 } 92 issuances = append(issuances, issuance) 93 94 case *SpendInput: 95 // create entry for prevout 96 prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} 97 src := &bc.ValueSource{ 98 Ref: &inp.SourceID, 99 Value: &inp.AssetAmount, 100 Position: inp.SourcePosition, 101 } 102 prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs 103 prevoutID := addEntry(prevout) 104 // create entry for spend 105 spend := bc.NewSpend(&prevoutID, uint64(i)) 106 spend.WitnessArguments = inp.Arguments 107 spendID := addEntry(spend) 108 // setup mux 109 muxSources[i] = &bc.ValueSource{ 110 Ref: &spendID, 111 Value: &inp.AssetAmount, 112 } 113 spends = append(spends, spend) 114 115 case *CoinbaseInput: 116 coinbase = bc.NewCoinbase(inp.Arbitrary) 117 coinbaseID := addEntry(coinbase) 118 119 out := tx.Outputs[0] 120 muxSources[i] = &bc.ValueSource{ 121 Ref: &coinbaseID, 122 Value: &out.AssetAmount, 123 } 124 } 125 } 126 127 mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}}) 128 muxID := addEntry(mux) 129 130 // connect the inputs to the mux 131 for _, spend := range spends { 132 spentOutput := entryMap[*spend.SpentOutputId].(*bc.Output) 133 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) 134 } 135 for _, issuance := range issuances { 136 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal) 137 } 138 139 if coinbase != nil { 140 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0) 141 } 142 143 // convert types.outputs to the bc.output 144 var resultIDs []*bc.Hash 145 for i, out := range tx.Outputs { 146 src := &bc.ValueSource{ 147 Ref: &muxID, 148 Value: &out.AssetAmount, 149 Position: uint64(i), 150 } 151 var resultID bc.Hash 152 if vmutil.IsUnspendable(out.ControlProgram) { 153 // retirement 154 r := bc.NewRetirement(src, uint64(i)) 155 resultID = addEntry(r) 156 } else { 157 // non-retirement 158 prog := &bc.Program{out.VMVersion, out.ControlProgram} 159 o := bc.NewOutput(src, prog, uint64(i)) 160 resultID = addEntry(o) 161 } 162 163 dest := &bc.ValueDestination{ 164 Value: src.Value, 165 Ref: &resultID, 166 Position: 0, 167 } 168 resultIDs = append(resultIDs, &resultID) 169 mux.WitnessDestinations = append(mux.WitnessDestinations, dest) 170 } 171 172 h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs) 173 return addEntry(h), h, entryMap 174 } 175 176 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) { 177 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Nonce, old.Bits) 178 return bc.EntryID(bh), bh 179 } 180 181 // MapBlock converts a types block to bc block 182 func MapBlock(old *Block) *bc.Block { 183 if old == nil { 184 return nil 185 } 186 187 b := new(bc.Block) 188 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader) 189 for _, oldTx := range old.Transactions { 190 b.Transactions = append(b.Transactions, oldTx.Tx) 191 } 192 return b 193 }