OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / bytom / protocol / bc / types / map.go
diff --git a/vendor/github.com/bytom/protocol/bc/types/map.go b/vendor/github.com/bytom/protocol/bc/types/map.go
new file mode 100644 (file)
index 0000000..4975bd7
--- /dev/null
@@ -0,0 +1,193 @@
+package types
+
+import (
+       "github.com/bytom/consensus"
+       "github.com/bytom/protocol/bc"
+       "github.com/bytom/protocol/vm"
+       "github.com/bytom/protocol/vm/vmutil"
+)
+
+// MapTx converts a types TxData object into its entries-based
+// representation.
+func MapTx(oldTx *TxData) *bc.Tx {
+       txID, txHeader, entries := mapTx(oldTx)
+       tx := &bc.Tx{
+               TxHeader: txHeader,
+               ID:       txID,
+               Entries:  entries,
+               InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
+       }
+
+       spentOutputIDs := make(map[bc.Hash]bool)
+       for id, e := range entries {
+               var ord uint64
+               switch e := e.(type) {
+               case *bc.Issuance:
+                       ord = e.Ordinal
+
+               case *bc.Spend:
+                       ord = e.Ordinal
+                       spentOutputIDs[*e.SpentOutputId] = true
+                       if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
+                               tx.GasInputIDs = append(tx.GasInputIDs, id)
+                       }
+
+               case *bc.Coinbase:
+                       ord = 0
+                       tx.GasInputIDs = append(tx.GasInputIDs, id)
+
+               default:
+                       continue
+               }
+
+               if ord >= uint64(len(oldTx.Inputs)) {
+                       continue
+               }
+               tx.InputIDs[ord] = id
+       }
+
+       for id := range spentOutputIDs {
+               tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
+       }
+       return tx
+}
+
+func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
+       entryMap = make(map[bc.Hash]bc.Entry)
+       addEntry := func(e bc.Entry) bc.Hash {
+               id := bc.EntryID(e)
+               entryMap[id] = e
+               return id
+       }
+
+       var (
+               spends    []*bc.Spend
+               issuances []*bc.Issuance
+               coinbase  *bc.Coinbase
+       )
+
+       muxSources := make([]*bc.ValueSource, len(tx.Inputs))
+       for i, input := range tx.Inputs {
+               switch inp := input.TypedInput.(type) {
+               case *IssuanceInput:
+                       nonceHash := inp.NonceHash()
+                       assetDefHash := inp.AssetDefinitionHash()
+                       value := input.AssetAmount()
+
+                       issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
+                       issuance.WitnessAssetDefinition = &bc.AssetDefinition{
+                               Data: &assetDefHash,
+                               IssuanceProgram: &bc.Program{
+                                       VmVersion: inp.VMVersion,
+                                       Code:      inp.IssuanceProgram,
+                               },
+                       }
+                       issuance.WitnessArguments = inp.Arguments
+                       issuanceID := addEntry(issuance)
+
+                       muxSources[i] = &bc.ValueSource{
+                               Ref:   &issuanceID,
+                               Value: &value,
+                       }
+                       issuances = append(issuances, issuance)
+
+               case *SpendInput:
+                       // create entry for prevout
+                       prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
+                       src := &bc.ValueSource{
+                               Ref:      &inp.SourceID,
+                               Value:    &inp.AssetAmount,
+                               Position: inp.SourcePosition,
+                       }
+                       prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
+                       prevoutID := addEntry(prevout)
+                       // create entry for spend
+                       spend := bc.NewSpend(&prevoutID, uint64(i))
+                       spend.WitnessArguments = inp.Arguments
+                       spendID := addEntry(spend)
+                       // setup mux
+                       muxSources[i] = &bc.ValueSource{
+                               Ref:   &spendID,
+                               Value: &inp.AssetAmount,
+                       }
+                       spends = append(spends, spend)
+
+               case *CoinbaseInput:
+                       coinbase = bc.NewCoinbase(inp.Arbitrary)
+                       coinbaseID := addEntry(coinbase)
+
+                       out := tx.Outputs[0]
+                       muxSources[i] = &bc.ValueSource{
+                               Ref:   &coinbaseID,
+                               Value: &out.AssetAmount,
+                       }
+               }
+       }
+
+       mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
+       muxID := addEntry(mux)
+
+       // connect the inputs to the mux
+       for _, spend := range spends {
+               spentOutput := entryMap[*spend.SpentOutputId].(*bc.Output)
+               spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
+       }
+       for _, issuance := range issuances {
+               issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
+       }
+
+       if coinbase != nil {
+               coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
+       }
+
+       // convert types.outputs to the bc.output
+       var resultIDs []*bc.Hash
+       for i, out := range tx.Outputs {
+               src := &bc.ValueSource{
+                       Ref:      &muxID,
+                       Value:    &out.AssetAmount,
+                       Position: uint64(i),
+               }
+               var resultID bc.Hash
+               if vmutil.IsUnspendable(out.ControlProgram) {
+                       // retirement
+                       r := bc.NewRetirement(src, uint64(i))
+                       resultID = addEntry(r)
+               } else {
+                       // non-retirement
+                       prog := &bc.Program{out.VMVersion, out.ControlProgram}
+                       o := bc.NewOutput(src, prog, uint64(i))
+                       resultID = addEntry(o)
+               }
+
+               dest := &bc.ValueDestination{
+                       Value:    src.Value,
+                       Ref:      &resultID,
+                       Position: 0,
+               }
+               resultIDs = append(resultIDs, &resultID)
+               mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
+       }
+
+       h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
+       return addEntry(h), h, entryMap
+}
+
+func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
+       bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Nonce, old.Bits)
+       return bc.EntryID(bh), bh
+}
+
+// MapBlock converts a types block to bc block
+func MapBlock(old *Block) *bc.Block {
+       if old == nil {
+               return nil
+       }
+
+       b := new(bc.Block)
+       b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
+       for _, oldTx := range old.Transactions {
+               b.Transactions = append(b.Transactions, oldTx.Tx)
+       }
+       return b
+}