diff --git a/api/api.go b/api/api.go index aaed95f49..dd6e02de1 100644 --- a/api/api.go +++ b/api/api.go @@ -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) diff --git a/api/contract.go b/api/contract.go index e1e9bafeb..c23b25d9e 100644 --- a/api/contract.go +++ b/api/contract.go @@ -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) +} diff --git a/contract/instance.go b/contract/instance.go index ffaf0bf62..f8dffbd31 100644 --- a/contract/instance.go +++ b/contract/instance.go @@ -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, } } diff --git a/contract/trace_scheduler.go b/contract/trace_scheduler.go index 543801924..e79f21b66 100644 --- a/contract/trace_scheduler.go +++ b/contract/trace_scheduler.go @@ -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...) } } diff --git a/contract/trace_service.go b/contract/trace_service.go index 9b8a081af..cc0a5d4c2 100644 --- a/contract/trace_service.go +++ b/contract/trace_service.go @@ -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 } } diff --git a/contract/trace_store.go b/contract/trace_store.go index 129013ef6..c0ca7e38c 100644 --- a/contract/trace_store.go +++ b/contract/trace_store.go @@ -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 diff --git a/contract/tracer.go b/contract/tracer.go index eefc854a9..f10951ced 100644 --- a/contract/tracer.go +++ b/contract/tracer.go @@ -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) diff --git a/node/node.go b/node/node.go index f7931e9cd..aed27ac1b 100644 --- a/node/node.go +++ b/node/node.go @@ -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()