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"
10 type mapHelper struct {
12 entryMap map[bc.Hash]bc.Entry
14 // data using during the map process
16 issuances []*bc.Issuance
20 muxSources []*bc.ValueSource
24 spentOutputIDs []bc.Hash
28 func newMapHelper(txData *TxData) *mapHelper {
31 entryMap: make(map[bc.Hash]bc.Entry),
32 spends: []*bc.Spend{},
33 issuances: []*bc.Issuance{},
34 vetos: []*bc.VetoInput{},
35 muxSources: make([]*bc.ValueSource, len(txData.Inputs)),
36 inputIDs: make([]bc.Hash, len(txData.Inputs)),
37 spentOutputIDs: []bc.Hash{},
38 resultIDs: []*bc.Hash{},
42 func (mh *mapHelper) addEntry(e bc.Entry) bc.Hash {
48 func (mh *mapHelper) generateTx() *bc.Tx {
49 header := bc.NewTxHeader(mh.txData.Version, mh.txData.SerializedSize, mh.txData.TimeRange, mh.resultIDs)
52 ID: mh.addEntry(header),
54 InputIDs: mh.inputIDs,
55 SpentOutputIDs: mh.spentOutputIDs,
59 func (mh *mapHelper) mapCoinbaseInput(i int, input *CoinbaseInput) {
60 mh.coinbase = bc.NewCoinbase(input.Arbitrary)
61 mh.inputIDs[i] = mh.addEntry(mh.coinbase)
62 var totalAmount uint64
63 for _, output := range mh.txData.Outputs {
64 totalAmount += output.Amount
66 mh.muxSources[i] = &bc.ValueSource{
68 Value: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: totalAmount},
72 func (mh *mapHelper) mapIssuanceInput(i int, input *IssuanceInput) {
73 nonceHash := input.NonceHash()
74 assetDefHash := input.AssetDefinitionHash()
75 assetID := input.AssetID()
76 value := bc.AssetAmount{AssetId: &assetID, Amount: input.Amount}
78 issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
79 issuance.WitnessAssetDefinition = &bc.AssetDefinition{
81 IssuanceProgram: &bc.Program{
82 VmVersion: input.VMVersion,
83 Code: input.IssuanceProgram,
87 issuance.WitnessArguments = input.Arguments
88 mh.issuances = append(mh.issuances, issuance)
89 mh.inputIDs[i] = mh.addEntry(issuance)
90 mh.muxSources[i] = &bc.ValueSource{
96 func (mh *mapHelper) mapSpendInput(i int, input *SpendInput) {
97 // create entry for prevout
98 prog := &bc.Program{VmVersion: input.VMVersion, Code: input.ControlProgram}
99 src := &bc.ValueSource{
100 Ref: &input.SourceID,
101 Value: &input.AssetAmount,
102 Position: input.SourcePosition,
105 prevout := bc.NewOriginalOutput(src, prog, input.StateData, 0) // ordinal doesn't matter for prevouts, only for result outputs
106 prevoutID := mh.addEntry(prevout)
108 // create entry for spend
109 spend := bc.NewSpend(&prevoutID, uint64(i))
110 spend.WitnessArguments = input.Arguments
111 mh.spends = append(mh.spends, spend)
112 mh.inputIDs[i] = mh.addEntry(spend)
113 mh.spentOutputIDs = append(mh.spentOutputIDs, prevoutID)
114 mh.muxSources[i] = &bc.ValueSource{
115 Ref: &mh.inputIDs[i],
116 Value: &input.AssetAmount,
120 func (mh *mapHelper) mapVetoInput(i int, input *VetoInput) {
121 prog := &bc.Program{VmVersion: input.VMVersion, Code: input.ControlProgram}
122 src := &bc.ValueSource{
123 Ref: &input.SourceID,
124 Value: &input.AssetAmount,
125 Position: input.SourcePosition,
128 prevout := bc.NewVoteOutput(src, prog, input.StateData, 0, input.Vote) // ordinal doesn't matter for prevouts, only for result outputs
129 prevoutID := mh.addEntry(prevout)
130 // create entry for VetoInput
131 vetoInput := bc.NewVetoInput(&prevoutID, uint64(i))
132 vetoInput.WitnessArguments = input.Arguments
133 mh.vetos = append(mh.vetos, vetoInput)
134 mh.inputIDs[i] = mh.addEntry(vetoInput)
135 mh.spentOutputIDs = append(mh.spentOutputIDs, prevoutID)
136 mh.muxSources[i] = &bc.ValueSource{
137 Ref: &mh.inputIDs[i],
138 Value: &input.AssetAmount,
142 func (mh *mapHelper) mapInputs() {
143 for i, input := range mh.txData.Inputs {
144 switch typedInput := input.TypedInput.(type) {
146 mh.mapIssuanceInput(i, typedInput)
148 mh.mapSpendInput(i, typedInput)
150 mh.mapVetoInput(i, typedInput)
152 mh.mapCoinbaseInput(i, typedInput)
154 panic("fail on handle transaction input")
159 func (mh *mapHelper) initMux() {
160 mh.mux = bc.NewMux(mh.muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
161 muxID := mh.addEntry(mh.mux)
163 // connect the inputs to the mux
164 for _, spend := range mh.spends {
165 spentOutput := mh.entryMap[*spend.SpentOutputId].(*bc.OriginalOutput)
166 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
169 for _, vetoInput := range mh.vetos {
170 voteOutput := mh.entryMap[*vetoInput.SpentOutputId].(*bc.VoteOutput)
171 vetoInput.SetDestination(&muxID, voteOutput.Source.Value, vetoInput.Ordinal)
174 for _, issuance := range mh.issuances {
175 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
178 if mh.coinbase != nil {
179 mh.coinbase.SetDestination(&muxID, mh.mux.Sources[0].Value, 0)
183 func (mh *mapHelper) mapOutputs() {
184 muxID := bc.EntryID(mh.mux)
185 for i, out := range mh.txData.Outputs {
186 src := &bc.ValueSource{Ref: &muxID, Value: &out.AssetAmount, Position: uint64(i)}
187 prog := &bc.Program{out.VMVersion, out.ControlProgram}
191 case vmutil.IsUnspendable(out.ControlProgram):
192 r := bc.NewRetirement(src, uint64(i))
193 resultID = mh.addEntry(r)
195 case out.OutputType() == OriginalOutputType:
196 o := bc.NewOriginalOutput(src, prog, out.StateData, uint64(i))
197 resultID = mh.addEntry(o)
199 case out.OutputType() == VoteOutputType:
200 voteOut, _ := out.TypedOutput.(*VoteOutput)
201 v := bc.NewVoteOutput(src, prog, out.StateData, uint64(i), voteOut.Vote)
202 resultID = mh.addEntry(v)
205 panic("fail on handle transaction output")
208 mh.resultIDs = append(mh.resultIDs, &resultID)
209 mh.mux.WitnessDestinations = append(mh.mux.WitnessDestinations, &bc.ValueDestination{
217 // MapTx converts a types TxData object into its entries-based
219 func MapTx(txData *TxData) *bc.Tx {
220 mh := newMapHelper(txData)
224 return mh.generateTx()
227 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
228 bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot)
229 return bc.EntryID(bh), bh
232 // MapBlock converts a types block to bc block
233 func MapBlock(old *Block) *bc.Block {
239 b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
240 for _, oldTx := range old.Transactions {
241 b.Transactions = append(b.Transactions, oldTx.Tx)