OSDN Git Service

fix_tracer_in_test (#2110)
authorPoseidon <shenao.78@163.com>
Fri, 17 Sep 2021 08:10:21 +0000 (16:10 +0800)
committerGitHub <noreply@github.com>
Fri, 17 Sep 2021 08:10:21 +0000 (16:10 +0800)
* fix_tracer_in_test

* remove debug print

* remove fmt

* remove fmt import

api/api.go
api/contract.go
contract/instance.go
contract/trace_scheduler.go
contract/trace_service.go
contract/trace_store.go
contract/tracer.go
node/node.go

index aaed95f..dd6e02d 100644 (file)
@@ -7,6 +7,7 @@ import (
        "sync"
        "time"
 
+       "github.com/bytom/bytom/contract"
        "github.com/kr/secureheader"
        log "github.com/sirupsen/logrus"
        cmn "github.com/tendermint/tmlibs/common"
@@ -52,12 +53,12 @@ type Response struct {
        Data        interface{} `json:"data,omitempty"`
 }
 
-//NewSuccessResponse success response
+// NewSuccessResponse success response
 func NewSuccessResponse(data interface{}) Response {
        return Response{Status: SUCCESS, Data: data}
 }
 
-//FormatErrResp format error response
+// FormatErrResp format error response
 func FormatErrResp(err error) (response Response) {
        response = Response{Status: FAIL}
        root := errors.Root(err)
@@ -82,7 +83,7 @@ func FormatErrResp(err error) (response Response) {
        return response
 }
 
-//NewErrorResponse error response
+// NewErrorResponse error response
 func NewErrorResponse(err error) Response {
        response := FormatErrResp(err)
        return response
@@ -109,6 +110,7 @@ type API struct {
        wallet          *wallet.Wallet
        accessTokens    *accesstoken.CredentialStore
        chain           *protocol.Chain
+       contractTracer  *contract.TraceService
        server          *http.Server
        handler         http.Handler
        blockProposer   *blockproposer.BlockProposer
@@ -178,11 +180,12 @@ type NetSync interface {
 }
 
 // NewAPI create and initialize the API
-func NewAPI(sync NetSync, wallet *wallet.Wallet, blockProposer *blockproposer.BlockProposer, chain *protocol.Chain, config *cfg.Config, token *accesstoken.CredentialStore, dispatcher *event.Dispatcher, notificationMgr *websocket.WSNotificationManager) *API {
+func NewAPI(sync NetSync, wallet *wallet.Wallet, blockProposer *blockproposer.BlockProposer, chain *protocol.Chain, traceService *contract.TraceService, config *cfg.Config, token *accesstoken.CredentialStore, dispatcher *event.Dispatcher, notificationMgr *websocket.WSNotificationManager) *API {
        api := &API{
                sync:            sync,
                wallet:          wallet,
                chain:           chain,
+               contractTracer:  traceService,
                accessTokens:    token,
                blockProposer:   blockProposer,
                eventDispatcher: dispatcher,
@@ -297,6 +300,10 @@ func (a *API) buildHandler() {
        m.Handle("/get-merkle-proof", jsonHandler(a.getMerkleProof))
        m.Handle("/get-vote-result", jsonHandler(a.getVoteResult))
 
+       m.Handle("/get-contract-instance", jsonHandler(a.getContractInstance))
+       m.Handle("/create-contract-instance", jsonHandler(a.createContractInstance))
+       m.Handle("/remove-contract-instance", jsonHandler(a.removeContractInstance))
+
        m.HandleFunc("/websocket-subscribe", a.websocketHandler)
 
        handler := walletHandler(m, walletEnable)
index e1e9baf..c23b25d 100644 (file)
@@ -8,6 +8,7 @@ import (
        "github.com/bytom/bytom/crypto/sha3pool"
        chainjson "github.com/bytom/bytom/encoding/json"
        "github.com/bytom/bytom/errors"
+       "github.com/bytom/bytom/protocol/bc"
        "github.com/bytom/bytom/protocol/vm/vmutil"
 )
 
@@ -105,3 +106,52 @@ func (a *API) listContracts(_ context.Context) Response {
 
        return NewSuccessResponse(cs)
 }
+
+type ContractInstance struct {
+       UTXOs       []*contract.UTXO     `json:"utxos"`
+       TxHash      *bc.Hash             `json:"tx_hash"`
+       Status      contract.Status      `json:"status"`
+       Unconfirmed []*contract.TreeNode `json:"unconfirmed"`
+}
+
+func (a *API) getContractInstance(_ context.Context, ins struct {
+       TraceID string `json:"trace_id"`
+}) Response {
+       instance, err := a.contractTracer.GetInstance(ins.TraceID)
+       if err != nil {
+               return NewErrorResponse(err)
+       }
+
+       return NewSuccessResponse(&ContractInstance{
+               UTXOs:       instance.UTXOs,
+               TxHash:      instance.TxHash,
+               Status:      instance.Status,
+               Unconfirmed: instance.Unconfirmed,
+       })
+}
+
+func (a *API) createContractInstance(_ context.Context, ins struct {
+       TxHash    chainjson.HexBytes `json:"tx_hash"`
+       BlockHash chainjson.HexBytes `json:"block_hash"`
+}) Response {
+       var txHash, blockHash [32]byte
+       copy(txHash[:], ins.TxHash)
+       copy(blockHash[:], ins.BlockHash)
+
+       traceIDs, err := a.contractTracer.CreateInstance(bc.NewHash(txHash), bc.NewHash(blockHash))
+       if err != nil {
+               return NewErrorResponse(err)
+       }
+
+       return NewSuccessResponse(traceIDs)
+}
+
+func (a *API) removeContractInstance(_ context.Context, ins struct {
+       TraceID string `json:"trace_id"`
+}) Response {
+       if err := a.contractTracer.RemoveInstance(ins.TraceID); err != nil {
+               return NewErrorResponse(err)
+       }
+
+       return NewSuccessResponse(nil)
+}
index ffaf0bf..f8dffbd 100644 (file)
@@ -15,25 +15,29 @@ const (
        OffChain
 )
 
-type treeNode struct {
-       TxHash   bc.Hash
-       UTXOs    []*UTXO
-       Children []*treeNode
+type TreeNode struct {
+       TxHash   bc.Hash     `json:"tx_hash"`
+       UTXOs    []*UTXO     `json:"utxos"`
+       Children []*TreeNode `json:"children"`
 }
 
 type Instance struct {
-       TraceID       string
-       UTXOs         []*UTXO
-       Unconfirmed   []*treeNode
-       Status        Status
-       ScannedHash   bc.Hash
-       ScannedHeight uint64
+       TraceID       string   `json:"trace_id"`
+       UTXOs         []*UTXO  `json:"utxos"`
+       TxHash        *bc.Hash `json:"tx_hash"`
+       Status        Status   `json:"status"`
+       ScannedHash   bc.Hash  `json:"scanned_hash"`
+       ScannedHeight uint64   `json:"scanned_height"`
+       Unconfirmed   []*TreeNode
 }
 
-func newInstance(inUTXOs, outUTXOs []*UTXO) *Instance {
+func newInstance(inUTXOs, outUTXOs []*UTXO, txHash bc.Hash, block *types.Block) *Instance {
        inst := &Instance{
-               TraceID: uuid.New().String(),
-               UTXOs:   outUTXOs,
+               TraceID:       uuid.New().String(),
+               TxHash:        &txHash,
+               UTXOs:         outUTXOs,
+               ScannedHeight: block.Height,
+               ScannedHash:   block.Hash(),
        }
        inst.Status = Lagging
        if len(outUTXOs) == 0 {
@@ -43,20 +47,32 @@ func newInstance(inUTXOs, outUTXOs []*UTXO) *Instance {
        return inst
 }
 
-func (i *Instance) transferTo(newUTXOs []*UTXO) *Instance {
+func (i *Instance) transferTo(newUTXOs []*UTXO, txHash bc.Hash) *Instance {
        inst := &Instance{
                TraceID:     i.TraceID,
                Status:      i.Status,
                Unconfirmed: i.Unconfirmed,
                UTXOs:       newUTXOs,
+               TxHash:      &txHash,
        }
        if len(newUTXOs) == 0 {
                inst.Status = Finalized
                inst.UTXOs = i.UTXOs
        }
+       inst.confirmTx(txHash)
        return inst
 }
 
+func (i *Instance) rollbackTo(newUTXOs []*UTXO) *Instance {
+       return &Instance{
+               TraceID:     i.TraceID,
+               Status:      InSync,
+               UTXOs:       newUTXOs,
+               TxHash:      nil,
+               Unconfirmed: nil,
+       }
+}
+
 func (i *Instance) confirmTx(txHash bc.Hash) {
        for _, node := range i.Unconfirmed {
                if node.TxHash == txHash {
@@ -67,72 +83,81 @@ func (i *Instance) confirmTx(txHash bc.Hash) {
        i.Unconfirmed = nil
 }
 
-type instanceTable struct {
+type instanceIndex struct {
        traceIdToInst  map[string]*Instance
        utxoHashToInst map[bc.Hash]*Instance
 }
 
-func newInstanceTable() *instanceTable {
-       return &instanceTable{
+func newInstanceIndex() *instanceIndex {
+       return &instanceIndex{
                traceIdToInst:  make(map[string]*Instance),
                utxoHashToInst: make(map[bc.Hash]*Instance),
        }
 }
 
-func (i *instanceTable) getByID(id string) *Instance {
+func (i *instanceIndex) getAll() []*Instance {
+       var instances []*Instance
+       for _, inst := range i.traceIdToInst {
+               instances = append(instances, inst)
+       }
+       return instances
+}
+
+func (i *instanceIndex) getByID(id string) *Instance {
        return i.traceIdToInst[id]
 }
 
-func (i *instanceTable) getByUTXO(utxoHash bc.Hash) *Instance {
+func (i *instanceIndex) getByUTXO(utxoHash bc.Hash) *Instance {
        return i.utxoHashToInst[utxoHash]
 }
 
-func (i *instanceTable) save(newInst *Instance) {
+func (i *instanceIndex) add(instance *Instance) {
+       i.traceIdToInst[instance.TraceID] = instance
+       for _, utxo := range instance.UTXOs {
+               i.utxoHashToInst[utxo.Hash] = instance
+       }
+}
+
+func (i *instanceIndex) save(newInst *Instance) {
        if old, ok := i.traceIdToInst[newInst.TraceID]; ok {
                for _, utxo := range old.UTXOs {
-                       delete(i.utxoHashToInst, utxo.hash)
+                       delete(i.utxoHashToInst, utxo.Hash)
                }
        }
        i.add(newInst)
 }
 
-func (i *instanceTable) remove(id string) {
+func (i *instanceIndex) remove(id string) {
        if inst, ok := i.traceIdToInst[id]; ok {
                delete(i.traceIdToInst, id)
                for _, utxo := range inst.UTXOs {
-                       delete(i.utxoHashToInst, utxo.hash)
+                       delete(i.utxoHashToInst, utxo.Hash)
                }
        }
 }
 
-func (i *instanceTable) add(instance *Instance) {
-       i.traceIdToInst[instance.TraceID] = instance
-       for _, utxo := range instance.UTXOs {
-               i.utxoHashToInst[utxo.hash] = instance
-       }
-}
-
 type UTXO struct {
-       hash      bc.Hash
-       assetID   bc.AssetID
-       amount    uint64
-       program   []byte
-       sourceID  bc.Hash
-       sourcePos uint64
-       stateData [][]byte
+       Hash      bc.Hash    `json:"hash"`
+       AssetID   bc.AssetID `json:"asset_id"`
+       Amount    uint64     `json:"amount"`
+       Program   []byte     `json:"program"`
+       SourceID  bc.Hash    `json:"source_id"`
+       SourcePos uint64     `json:"source_pos"`
+       StateData [][]byte   `json:"state_data"`
 }
 
 func inputToUTXO(tx *types.Tx, index int) *UTXO {
        input := tx.Inputs[index]
+       outputID, _ := input.SpentOutputID()
        spendInput := input.TypedInput.(*types.SpendInput)
        return &UTXO{
-               hash:      tx.InputIDs[index],
-               assetID:   input.AssetID(),
-               amount:    input.Amount(),
-               program:   input.ControlProgram(),
-               sourceID:  spendInput.SourceID,
-               sourcePos: spendInput.SourcePosition,
-               stateData: spendInput.StateData,
+               Hash:      outputID,
+               AssetID:   input.AssetID(),
+               Amount:    input.Amount(),
+               Program:   input.ControlProgram(),
+               SourceID:  spendInput.SourceID,
+               SourcePos: spendInput.SourcePosition,
+               StateData: spendInput.StateData,
        }
 }
 
@@ -141,12 +166,12 @@ func outputToUTXO(tx *types.Tx, index int) *UTXO {
        outputID := tx.OutputID(index)
        originalOutput, _ := tx.OriginalOutput(*outputID)
        return &UTXO{
-               hash:      *outputID,
-               assetID:   *output.AssetId,
-               amount:    output.Amount,
-               program:   output.ControlProgram,
-               sourceID:  *originalOutput.Source.Ref,
-               sourcePos: uint64(index),
-               stateData: originalOutput.StateData,
+               Hash:      *outputID,
+               AssetID:   *output.AssetId,
+               Amount:    output.Amount,
+               Program:   output.ControlProgram,
+               SourceID:  *originalOutput.Source.Ref,
+               SourcePos: uint64(index),
+               StateData: originalOutput.StateData,
        }
 }
index 5438019..e79f21b 100644 (file)
@@ -49,98 +49,100 @@ func (t *traceScheduler) processLoop() {
        defer ticker.Stop()
 
        for range ticker.C {
-               jobs, beginHeight := t.prepareJobs()
+               jobs, beginHeight, beginHash := t.prepareJobs()
                if len(jobs) == 0 {
                        continue
                }
 
-               t.tracer = newTracer(nil)
+               t.tracer = newTracer(jobs[beginHash])
 
-               var prevHash *bc.Hash
-               catchedJobs := make(map[bc.Hash][]*Instance)
-               for height := beginHeight + 1; ; height++ {
-                       if ok, err := t.tryAttach(height, prevHash, jobs, catchedJobs); err != nil {
+               for height, blockHash := beginHeight, beginHash; ; height++ {
+                       if bestHeight := t.tracerService.BestHeight(); height == bestHeight {
+                               if err := t.finishJobs(jobs, blockHash); err != nil {
+                                       log.WithField("err", err).Error("finish jobs")
+                                       break
+                               }
+                       }
+
+                       if ok, err := t.tryAttach(height+1, &blockHash, jobs); err != nil {
                                log.WithField("err", err).Error("try attach on trace scheduler")
                                break
                        } else if !ok {
-                               if err := t.detach(prevHash, catchedJobs); err != nil {
+                               if err := t.detach(&blockHash, jobs); err != nil {
                                        log.WithField("err", err).Error("detach on trace scheduler")
                                        break
                                }
                                height -= 2
                        }
-                       if bestHeight := t.tracerService.BestHeight(); height == bestHeight {
-                               if err := t.finishJobs(jobs, catchedJobs, *prevHash); err != nil {
-                                       log.WithField("err", err).Error("finish jobs")
-                                       break
-                               }
-                       }
                }
        }
 }
 
-func (t *traceScheduler) prepareJobs() (map[bc.Hash][]*Instance, uint64) {
-       var beginHeight uint64 = math.MaxUint64
+func (t *traceScheduler) prepareJobs() (map[bc.Hash][]*Instance, uint64, bc.Hash) {
+       beginHeight, beginHash := uint64(math.MaxUint64), bc.Hash{}
        hashToJobs := make(map[bc.Hash][]*Instance)
        t.instances.Range(func(_, value interface{}) bool {
                inst := value.(*Instance)
                hashToJobs[inst.ScannedHash] = append(hashToJobs[inst.ScannedHash], inst)
                if inst.ScannedHeight < beginHeight {
                        beginHeight = inst.ScannedHeight
+                       beginHash = inst.ScannedHash
                }
                return true
        })
-       return hashToJobs, beginHeight
+       return hashToJobs, beginHeight, beginHash
 }
 
-func (t *traceScheduler) tryAttach(height uint64, prevHash *bc.Hash, jobs, catchedJobs map[bc.Hash][]*Instance) (bool, error) {
+func (t *traceScheduler) tryAttach(height uint64, blockHash *bc.Hash, jobs map[bc.Hash][]*Instance) (bool, error) {
        block, err := t.infra.Chain.GetBlockByHeight(height)
        if err != nil {
                return false, err
        }
 
-       if prevHash != nil && block.PreviousBlockHash != *prevHash {
+       if block.PreviousBlockHash != *blockHash {
                return false, nil
        }
 
-       if instances, ok := jobs[block.PreviousBlockHash]; ok {
+       t.tracer.applyBlock(block)
+       *blockHash = block.Hash()
+
+       if instances, ok := jobs[block.Hash()]; ok {
                t.tracer.addInstances(instances)
-               catchedJobs[block.PreviousBlockHash] = instances
        }
-
-       t.tracer.applyBlock(block)
-       *prevHash = block.Hash()
        return true, nil
 }
 
-func (t *traceScheduler) detach(prevHash *bc.Hash, catchedJobs map[bc.Hash][]*Instance) error {
-       prevBlock, err := t.infra.Chain.GetBlockByHash(prevHash)
+func (t *traceScheduler) detach(blockHash *bc.Hash, jobs map[bc.Hash][]*Instance) error {
+       block, err := t.infra.Chain.GetBlockByHash(blockHash)
        if err != nil {
                return err
        }
 
-       if instances, ok := catchedJobs[prevBlock.Hash()]; ok {
+       if instances, ok := jobs[block.Hash()]; ok {
                for _, inst := range instances {
                        t.tracer.removeInstance(inst.TraceID)
                }
-               delete(catchedJobs, prevBlock.Hash())
        }
 
-       t.tracer.detachBlock(prevBlock)
-       *prevHash = prevBlock.PreviousBlockHash
+       t.tracer.detachBlock(block)
+       *blockHash = block.PreviousBlockHash
        return nil
 }
 
-func (t *traceScheduler) finishJobs(jobs, catchedJobs map[bc.Hash][]*Instance, scannedHash bc.Hash) error {
-       var inSyncInstances, offChainInstances []*Instance
-       for hash, instances := range jobs {
-               if _, ok := catchedJobs[hash]; !ok {
-                       offChainInstances = append(offChainInstances, instances...)
-                       for _, inst := range instances {
+func (t *traceScheduler) finishJobs(jobs map[bc.Hash][]*Instance, scannedHash bc.Hash) error {
+       inSyncInstances := t.tracer.allInstances()
+       inSyncMap := make(map[string]bool)
+       for _, inst := range inSyncInstances {
+               inSyncMap[inst.TraceID] = true
+       }
+
+       var offChainInstances []*Instance
+       for _, instances := range jobs {
+               for _, inst := range instances {
+                       if _, ok := inSyncMap[inst.TraceID]; !ok {
                                inst.Status = OffChain
+                               offChainInstances = append(offChainInstances, inst)
                        }
-               } else {
-                       inSyncInstances = append(inSyncInstances, instances...)
                }
        }
 
index 9b8a081..cc0a5d4 100644 (file)
@@ -23,7 +23,7 @@ type TraceService struct {
        tracer           *tracer
        infra            *Infrastructure
        scheduler        *traceScheduler
-       unconfirmedIndex map[bc.Hash]*treeNode
+       unconfirmedIndex map[bc.Hash]*TreeNode
        bestHeight       uint64
        bestHash         bc.Hash
 }
@@ -37,7 +37,7 @@ func NewTraceService(infra *Infrastructure) *TraceService {
        chainStatus := infra.Repository.GetChainStatus()
        if chainStatus == nil {
                chainStatus.BlockHeight, chainStatus.BlockHash = infra.Chain.BestChain()
-               if err := infra.Repository.SaveChainStatus(chainStatus);  err != nil {
+               if err := infra.Repository.SaveChainStatus(chainStatus); err != nil {
                        logrus.WithField("err", err).Fatal("init chain status for trace service")
                }
        }
@@ -49,7 +49,7 @@ func NewTraceService(infra *Infrastructure) *TraceService {
                infra:            infra,
                tracer:           newTracer(inSyncInstances),
                scheduler:        scheduler,
-               unconfirmedIndex: make(map[bc.Hash]*treeNode),
+               unconfirmedIndex: make(map[bc.Hash]*TreeNode),
                bestHeight:       chainStatus.BlockHeight,
                bestHash:         chainStatus.BlockHash,
        }
@@ -111,14 +111,14 @@ func (t *TraceService) AddUnconfirmedTx(tx *types.Tx) {
                        return
                }
 
-               treeNode := &treeNode{TxHash: tx.ID, UTXOs: outUTXOs}
-               if inst := t.tracer.table.getByUTXO(inUTXOs[0].hash); inst != nil {
+               treeNode := &TreeNode{TxHash: tx.ID, UTXOs: outUTXOs}
+               if inst := t.tracer.table.getByUTXO(inUTXOs[0].Hash); inst != nil {
                        inst.Unconfirmed = append(inst.Unconfirmed, treeNode)
                        t.addToUnconfirmedIndex(treeNode, outUTXOs)
                        return
                }
 
-               if parent, ok := t.unconfirmedIndex[inUTXOs[0].hash]; ok {
+               if parent, ok := t.unconfirmedIndex[inUTXOs[0].Hash]; ok {
                        parent.Children = append(parent.Children, treeNode)
                        t.addToUnconfirmedIndex(treeNode, outUTXOs)
                }
@@ -147,7 +147,7 @@ func (t *TraceService) CreateInstance(txHash, blockHash bc.Hash) ([]string, erro
 
        var traceIDs []string
        for _, transfer := range transfers {
-               inst := newInstance(transfer.inUTXOs, transfer.outUTXOs)
+               inst := newInstance(transfer.inUTXOs, transfer.outUTXOs, txHash, block)
                traceIDs = append(traceIDs, inst.TraceID)
                if err := t.addNewTraceJob(inst, block); err != nil {
                        return nil, err
@@ -177,6 +177,10 @@ func (t *TraceService) takeOverInstances(instances []*Instance, blockHash bc.Has
                return false
        }
 
+       for _, inst := range instances {
+               inst.Status = InSync
+       }
+
        if err := t.infra.Repository.SaveInstances(instances); err != nil {
                logrus.WithField("err", err).Error("save instances when take over instances")
                return false
@@ -192,8 +196,6 @@ func (t *TraceService) addNewTraceJob(inst *Instance, block *types.Block) error
        }
 
        if inst.Status != Finalized {
-               inst.ScannedHash = block.Hash()
-               inst.ScannedHeight = block.Height
                if err := t.scheduler.addNewJob(inst); err != nil {
                        return err
                }
@@ -201,9 +203,9 @@ func (t *TraceService) addNewTraceJob(inst *Instance, block *types.Block) error
        return nil
 }
 
-func (t *TraceService) addToUnconfirmedIndex(treeNode *treeNode, utxos []*UTXO) {
+func (t *TraceService) addToUnconfirmedIndex(treeNode *TreeNode, utxos []*UTXO) {
        for _, utxo := range utxos {
-               t.unconfirmedIndex[utxo.hash] = treeNode
+               t.unconfirmedIndex[utxo.Hash] = treeNode
        }
 }
 
index 129013e..c0ca7e3 100644 (file)
@@ -51,7 +51,7 @@ func (t *TraceStore) GetInstance(traceID string) (*Instance, error) {
 
 // LoadInstances used to load all instances in db
 func (t *TraceStore) LoadInstances() ([]*Instance, error) {
-       iter := t.db.Iterator()
+       iter := t.db.IteratorPrefix(instancePrefixKey)
        defer iter.Release()
 
        var instances []*Instance
index eefc854..f10951c 100644 (file)
@@ -8,17 +8,21 @@ import (
 )
 
 type tracer struct {
-       table *instanceTable
+       table *instanceIndex
 }
 
 func newTracer(instances []*Instance) *tracer {
-       table := newInstanceTable()
+       table := newInstanceIndex()
        for _, inst := range instances {
                table.save(inst)
        }
        return &tracer{table: table}
 }
 
+func (t *tracer) allInstances() []*Instance {
+       return t.table.getAll()
+}
+
 func (t *tracer) addInstances(instances []*Instance) {
        for _, inst := range instances {
                t.table.save(inst)
@@ -38,9 +42,8 @@ func (t *tracer) applyBlock(block *types.Block) []*Instance {
                                continue
                        }
 
-                       if inst := t.table.getByUTXO(transfer.inUTXOs[0].hash); inst != nil {
-                               newInst := inst.transferTo(transfer.outUTXOs)
-                               newInst.confirmTx(tx.ID)
+                       if inst := t.table.getByUTXO(transfer.inUTXOs[0].Hash); inst != nil {
+                               newInst := inst.transferTo(transfer.outUTXOs, tx.ID)
                                newInstances = append(newInstances, newInst)
                        }
                }
@@ -51,14 +54,13 @@ func (t *tracer) applyBlock(block *types.Block) []*Instance {
 
 func (t *tracer) detachBlock(block *types.Block) []*Instance {
        var newInstances []*Instance
-       for i := len(block.Transactions); i >= 0; i-- {
+       for i := len(block.Transactions) - 1; i >= 0; i-- {
                tx := block.Transactions[i]
                transfers := parseTransfers(tx)
                for _, transfer := range transfers {
                        utxos := append(transfer.outUTXOs, transfer.inUTXOs...)
-                       if inst := t.table.getByUTXO(utxos[0].hash); inst != nil {
-                               newInst := inst.transferTo(transfer.inUTXOs)
-                               newInst.Unconfirmed = nil
+                       if inst := t.table.getByUTXO(utxos[0].Hash); inst != nil {
+                               newInst := inst.rollbackTo(transfer.inUTXOs)
                                newInstances = append(newInstances, newInst)
                        }
                }
@@ -93,7 +95,7 @@ func parseTransfers(tx *types.Tx) []*transfer {
 func groupUTXOs(utxos []*UTXO) map[string][]*UTXO {
        groupUTXOs := make(map[string][]*UTXO)
        for _, utxo := range utxos {
-               program := hex.EncodeToString(utxo.program)
+               program := hex.EncodeToString(utxo.Program)
                groupUTXOs[program] = append(groupUTXOs[program], utxo)
        }
        return groupUTXOs
@@ -102,19 +104,23 @@ func groupUTXOs(utxos []*UTXO) map[string][]*UTXO {
 func parseContractUTXOs(tx *types.Tx) ([]*UTXO, []*UTXO) {
        var inUTXOs, outUTXOs []*UTXO
        for i, input := range tx.Inputs {
-               if segwit.IsP2WSHScript(input.ControlProgram()) {
+               if isContract(input.ControlProgram()) {
                        inUTXOs = append(inUTXOs, inputToUTXO(tx, i))
                }
        }
 
        for i, output := range tx.Outputs {
-               if segwit.IsP2WSHScript(output.ControlProgram) {
+               if isContract(output.ControlProgram) {
                        outUTXOs = append(outUTXOs, outputToUTXO(tx, i))
                }
        }
        return inUTXOs, outUTXOs
 }
 
+func isContract(program []byte) bool {
+       return !(segwit.IsP2WPKHScript(program) || segwit.IsP2WSHScript(program) || segwit.IsStraightforward(program))
+}
+
 func (t *tracer) saveInstances(instances []*Instance) {
        for _, inst := range instances {
                t.table.save(inst)
index f7931e9..aed27ac 100644 (file)
@@ -51,6 +51,7 @@ type Node struct {
        notificationMgr *websocket.WSNotificationManager
        api             *api.API
        chain           *protocol.Chain
+       traceService    *contract.TraceService
        blockProposer   *blockproposer.BlockProposer
        miningEnable    bool
 }
@@ -79,7 +80,7 @@ func NewNode(config *cfg.Config) *Node {
                cmn.Exit(cmn.Fmt("Failed to create chain structure: %v", err))
        }
 
-       startTraceUpdater(chain, config)
+       traceService := startTraceUpdater(chain, config)
 
        var accounts *account.Manager
        var assets *asset.Registry
@@ -133,6 +134,7 @@ func NewNode(config *cfg.Config) *Node {
                accessTokens:    accessTokens,
                wallet:          wallet,
                chain:           chain,
+               traceService:    traceService,
                miningEnable:    config.Mining,
                notificationMgr: notificationMgr,
        }
@@ -142,12 +144,13 @@ func NewNode(config *cfg.Config) *Node {
        return node
 }
 
-func startTraceUpdater(chain *protocol.Chain, cfg *cfg.Config) {
+func startTraceUpdater(chain *protocol.Chain, cfg *cfg.Config) *contract.TraceService {
        db := dbm.NewDB("trace", cfg.DBBackend, cfg.DBDir())
        store := contract.NewTraceStore(db)
        tracerService := contract.NewTraceService(contract.NewInfrastructure(chain, store))
        traceUpdater := contract.NewTraceUpdater(tracerService, chain)
        go traceUpdater.Sync()
+       return tracerService
 }
 
 func initNodeConfig(config *cfg.Config) error {
@@ -196,7 +199,7 @@ func launchWebBrowser(port string) {
 }
 
 func (n *Node) initAndstartAPIServer() {
-       n.api = api.NewAPI(n.syncManager, n.wallet, n.blockProposer, n.chain, n.config, n.accessTokens, n.eventDispatcher, n.notificationMgr)
+       n.api = api.NewAPI(n.syncManager, n.wallet, n.blockProposer, n.chain, n.traceService, n.config, n.accessTokens, n.eventDispatcher, n.notificationMgr)
 
        listenAddr := env.String("LISTEN", n.config.ApiAddress)
        env.Parse()