From 27da19c2c5b4397d5f00e3a218f05723b8c70725 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Wed, 13 Apr 2022 15:21:13 +0100 Subject: [PATCH 01/10] Fixed actor tests - Fixed bug in actors where downloads were being retried when they shouldn't - Added type assertions to internaltypes - Fixed empty func in peer.go --- consensus/dman/actors.go | 70 +++++++++++++++++++++++++++------ consensus/dman/actors_test.go | 17 ++++++-- consensus/dman/internaltypes.go | 12 ++++++ middleware/peer.go | 4 +- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/consensus/dman/actors.go b/consensus/dman/actors.go index 8f72fd35..4dca2c4c 100644 --- a/consensus/dman/actors.go +++ b/consensus/dman/actors.go @@ -107,37 +107,41 @@ func (a *RootActor) CleanCache(txn *badger.Txn, height uint32) error { // DownloadPendingTx downloads txs that are pending from remote peers func (a *RootActor) DownloadPendingTx(height, round uint32, txHash []byte) { req := NewTxDownloadRequest(txHash, PendingTxRequest, height, round) - a.download(req, false) + a.download(req, true) } // DownloadPendingTx downloads txs that are mined from remote peers func (a *RootActor) DownloadMinedTx(height, round uint32, txHash []byte) { req := NewTxDownloadRequest(txHash, MinedTxRequest, height, round) - a.download(req, false) + a.download(req, true) } func (a *RootActor) DownloadTx(height, round uint32, txHash []byte) { req := NewTxDownloadRequest(txHash, PendingAndMinedTxRequest, height, round) - a.download(req, false) + a.download(req, true) } // DownloadBlockHeader downloads block headers from remote peers func (a *RootActor) DownloadBlockHeader(height, round uint32) { req := NewBlockHeaderDownloadRequest(height, round, BlockHeaderRequest) - a.download(req, false) + a.download(req, true) } func (a *RootActor) download(b DownloadRequest, retry bool) { + a.logger.Infof("RA got download(). downloadRequest: %#v, retry: %#v, ", b, retry) select { case <-a.closeChan: + a.logger.Infof("RA got download() <-a.closeChan") return default: + a.logger.Infof("RA got download() default") a.wg.Add(1) go a.doDownload(b, retry) } } func (a *RootActor) doDownload(b DownloadRequest, retry bool) { + a.logger.Infof("RA got doDownload(). downloadRequest: %#v, retry: %#v, ", b, retry) defer a.wg.Done() switch b.DownloadType() { case PendingTxRequest, MinedTxRequest: @@ -160,7 +164,7 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { case <-a.closeChan: return case a.dispatchQ <- b: - a.await(b) + a.await(b, retry) } case PendingAndMinedTxRequest: ok := func() bool { @@ -200,7 +204,7 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { case <-a.closeChan: return case a.dispatchQ <- bc0: - a.await(bc0) + a.await(bc0, retry) } }() go func() { @@ -209,7 +213,7 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { case <-a.closeChan: return case a.dispatchQ <- bc1: - a.await(bc1) + a.await(bc1, retry) } }() select { @@ -241,25 +245,31 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { a.reqs[b.Identifier()] = true return true }() + a.logger.Infof("RA got doDownload() BlockHeaderRequest: b: %#v, retry: %v, ok: %v", b, retry, ok) if !ok { return } select { case <-a.closeChan: + a.logger.Infof("RA got doDownload() BlockHeaderRequest <-a.closeChan") return case a.dispatchQ <- b: - a.await(b) + a.logger.Infof("RA got doDownload() BlockHeaderRequest a.dispatchQ <- b") + a.await(b, retry) } default: panic(b.DownloadType()) } } -func (a *RootActor) await(req DownloadRequest) { +func (a *RootActor) await(req DownloadRequest, retry bool) { + a.logger.Info("RA got await()") select { case <-a.closeChan: + a.logger.Infof("RA got await() <-a.closeChan. req: %#v", req) return case resp := <-req.ResponseChan(): + a.logger.Infof("RA got await() resp := <-req.ResponseChan(). resp: %#v, req: %#v", resp, req) if resp == nil { return } @@ -270,7 +280,9 @@ func (a *RootActor) await(req DownloadRequest) { exists := a.txc.Contains(r.TxHash) if !exists { utils.DebugTrace(a.logger, r.Err) - defer a.download(req, true) + if retry { + defer a.download(req, true) + } } return } @@ -284,25 +296,34 @@ func (a *RootActor) await(req DownloadRequest) { if ok { return } - defer a.download(req, true) + if retry { + defer a.download(req, true) + } case BlockHeaderRequest: r := resp.(*BlockHeaderDownloadResponse) + a.logger.Infof("RA got await() BlockHeaderRequest. resp: %#v, req: %#v, r: %#v", resp, req, r) if r.Err != nil { utils.DebugTrace(a.logger, r.Err) - defer a.download(req, true) + if retry { + defer a.download(req, true) + } return } ok := func() bool { if err := a.bhc.Add(r.BH); err != nil { + a.logger.Warnf("error adding BH to cache: %v", err) utils.DebugTrace(a.logger, err) return false } return true }() + a.logger.Infof("RA got await() BlockHeaderRequest. ok: %v", ok) if ok { return } - defer a.download(req, true) + if retry { + defer a.download(req, true) + } default: panic(req.DownloadType()) } @@ -349,9 +370,11 @@ func (a *blockActor) getHeight() uint32 { } func (a *blockActor) run() { + a.Logger.Info("BA got run()") for { select { case <-a.closeChan: + a.Logger.Info("BA got run() <-a.closeChan") return case req := <-a.WorkQ: ok := func() bool { @@ -363,6 +386,7 @@ func (a *blockActor) run() { } return true }() + a.Logger.Infof("BA got run() req := <-a.WorkQ | ok: %v, req: %#v", ok, req) if !ok { continue } @@ -372,6 +396,7 @@ func (a *blockActor) run() { } func (a *blockActor) await(req DownloadRequest) { + a.Logger.Info("BA got await()") var subReq DownloadRequest switch req.DownloadType() { case PendingTxRequest, MinedTxRequest: @@ -384,19 +409,24 @@ func (a *blockActor) await(req DownloadRequest) { } case BlockHeaderRequest: reqTyped := req.(*BlockHeaderDownloadRequest) + a.Logger.Infof("BA got run() BlockHeaderRequest | reqTyped: %v", reqTyped) subReq = NewBlockHeaderDownloadRequest(reqTyped.Height, reqTyped.Round, reqTyped.Dtype) select { case <-a.closeChan: + a.Logger.Infof("BA got run() BlockHeaderRequest <-a.closeChan") return case a.dispatchQ <- subReq: + a.Logger.Infof("BA got run() BlockHeaderRequest a.dispatchQ <- subReq") } default: panic(fmt.Sprintf("req download type not found: %v", req.DownloadType())) } select { case <-a.closeChan: + a.Logger.Infof("BA got run() <-a.closeChan") return case resp := <-subReq.ResponseChan(): + a.Logger.Infof("BA got run() resp := <-subReq.ResponseChan() | resp: %#v", resp) if resp == nil { close(req.ResponseChan()) return @@ -409,14 +439,17 @@ func (a *blockActor) await(req DownloadRequest) { } return true }() + a.Logger.Infof("BA got run() resp := <-subReq.ResponseChan() | ok: %v", ok) if !ok { close(req.ResponseChan()) return } select { case <-a.closeChan: + a.Logger.Infof("BA got run() last <-a.closeChan") return case req.ResponseChan() <- resp: + a.Logger.Infof("BA got run() last req.ResponseChan() <- resp") } } } @@ -464,11 +497,14 @@ func (a *downloadActor) start() { } func (a *downloadActor) run() { + a.Logger.Info("downloadActor got run()") for { select { case <-a.closeChan: + a.Logger.Info("downloadActor got run() <-a.closeChan") return case req := <-a.WorkQ: + a.Logger.Infof("downloadActor got run() req := <-a.WorkQ. req: %#v", req) switch req.DownloadType() { case PendingTxRequest: select { @@ -487,7 +523,9 @@ func (a *downloadActor) run() { case BlockHeaderRequest: select { case a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest): + a.Logger.Infof("downloadActor got run() BlockHeaderRequest. a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest)") default: + a.Logger.Infof("downloadActor got run() BlockHeaderRequest. default") a.bha.start() a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest) } @@ -671,10 +709,13 @@ func (a *blockHeaderDownloadActor) start() { } func (a *blockHeaderDownloadActor) run() { + a.Logger.Info("blockHeaderDownloadActor got run()") for { select { case <-time.After(10 * time.Second): a.Lock() + a.Logger.Infof("blockHeaderDownloadActor got run() <-time.After(10 * time.Second). a.numWorkers: %v", a.numWorkers) + if a.numWorkers > 1 { a.numWorkers-- a.Unlock() @@ -682,8 +723,10 @@ func (a *blockHeaderDownloadActor) run() { } a.Unlock() case <-a.closeChan: + a.Logger.Info("blockHeaderDownloadActor got run() <-a.closeChan") return case reqOrig := <-a.WorkQ: + a.Logger.Infof("blockHeaderDownloadActor got run() reqOrig := <-a.WorkQ. reqOrig: %#v", reqOrig) bh, err := func(req *BlockHeaderDownloadRequest) (*objs.BlockHeader, error) { opts := []grpc.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(backoffAmount*time.Millisecond, .1)), @@ -703,6 +746,7 @@ func (a *blockHeaderDownloadActor) run() { } return bhLst[0], nil }(reqOrig) + a.Logger.Infof("blockHeaderDownloadActor got run() reqOrig := <-a.WorkQ. bh: %#v, err: %v", bh, err) reqOrig.ResponseChan() <- NewBlockHeaderDownloadResponse(reqOrig, bh, BlockHeaderRequest, err) } } diff --git a/consensus/dman/actors_test.go b/consensus/dman/actors_test.go index 016a6fb7..88b955bd 100644 --- a/consensus/dman/actors_test.go +++ b/consensus/dman/actors_test.go @@ -7,6 +7,7 @@ import ( "strconv" "sync" "testing" + "time" "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" @@ -74,9 +75,15 @@ type testingProxy struct { skipCallCheck bool } +// assert struct `testingProxy` implements `reqBusView` , `txMarshaller`, `databaseView` and `typeProxyIface` interfaces +var _ reqBusView = &testingProxy{} +var _ txMarshaller = &testingProxy{} +var _ databaseView = &testingProxy{} +var _ typeProxyIface = &testingProxy{} + func (trb *testingProxy) checkExpect() error { if trb.callIndex != len(trb.expectedCalls) { - return fmt.Errorf("Missing calls: %v", trb.expectedCalls[trb.callIndex:]) + return fmt.Errorf("Missing calls: %v, callIndex: %v, expectedCalls: %v", trb.expectedCalls[trb.callIndex:], trb.callIndex, len(trb.expectedCalls)) } return nil } @@ -154,13 +161,14 @@ func (trb *testingProxy) RequestP2PGetBlockHeaders(ctx context.Context, blockNum trb.callIndex++ }() cType := blockHeaderCall + fmt.Println("RequestP2PGetBlockHeaders()") trb.Lock() defer trb.Unlock() if trb.callIndex == len(trb.expectedCalls) { - panic(fmt.Sprintf("got unexpected call of type %s : expected calls %v", cType, trb.expectedCalls)) + panic(fmt.Sprintf("got unexpected call of type %s : expected calls %v, callIndex %v", cType, trb.expectedCalls, trb.callIndex)) } if trb.expectedCalls[trb.callIndex] != cType { - panic(fmt.Sprintf("got unexpcted call of type %s at index %v : expected calls %v", cType, trb.callIndex, trb.expectedCalls)) + panic(fmt.Sprintf("got unexpcted call of type %s at index %v : expected calls %v, callIndex %v", cType, trb.callIndex, trb.expectedCalls, trb.callIndex)) } if ctx == nil { panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) @@ -278,10 +286,13 @@ func TestRootActor_download(t *testing.T) { defer ra.Close() trb.expect(tt.proxyCalls, tt.proxyReturns) ra.download(tt.args.b, false) + t.Log("waiting on download from RA2") + <-time.After(5 * time.Second) // allow some time for actors to do their thing }() }) if tt.args.check { if err := trb.checkExpect(); err != nil { + // t.Logf("error %v", tt.name) t.Fatal(err) } } diff --git a/consensus/dman/internaltypes.go b/consensus/dman/internaltypes.go index 021d9a45..e507576d 100644 --- a/consensus/dman/internaltypes.go +++ b/consensus/dman/internaltypes.go @@ -82,6 +82,9 @@ type TxDownloadRequest struct { responseChan chan DownloadResponse } +// assert struct TxDownloadRequest implements DownloadRequest interface +var _ DownloadRequest = &TxDownloadRequest{} + func (r *TxDownloadRequest) DownloadType() DownloadType { return r.Dtype } @@ -126,6 +129,9 @@ type TxDownloadResponse struct { Round uint32 `json:"round,omitempty"` } +// assert struct TxDownloadResponse implements DownloadResponse interface +var _ DownloadResponse = &TxDownloadResponse{} + func (r *TxDownloadResponse) DownloadType() DownloadType { return r.Dtype } @@ -160,6 +166,9 @@ type BlockHeaderDownloadRequest struct { responseChan chan DownloadResponse } +// assert struct BlockHeaderDownloadRequest implements DownloadRequest interface +var _ DownloadRequest = &BlockHeaderDownloadRequest{} + func (r *BlockHeaderDownloadRequest) DownloadType() DownloadType { return r.Dtype } @@ -202,6 +211,9 @@ type BlockHeaderDownloadResponse struct { Round uint32 `json:"round,omitempty"` } +// assert struct BlockHeaderDownloadResponse implements DownloadResponse interface +var _ DownloadResponse = &BlockHeaderDownloadResponse{} + func (r *BlockHeaderDownloadResponse) IsResponse() bool { return true } diff --git a/middleware/peer.go b/middleware/peer.go index be82dda8..a08d2983 100644 --- a/middleware/peer.go +++ b/middleware/peer.go @@ -38,7 +38,9 @@ func (opt *PeerCallOption) setPeer(p PeerClient) { // NewPeerInterceptor is a function that builds a grpc.CallOption that will // return a peer ref to the caller func NewPeerInterceptor() *PeerCallOption { - opt := &PeerCallOption{EmptyCallOption: &grpc.EmptyCallOption{}, Peer: nil} + opt := &PeerCallOption{EmptyCallOption: &grpc.EmptyCallOption{}, Peer: func() PeerClient { + return peerClient{} + }} return opt } From 538ad3bb107514e13f6cc3beb9939b5ee1136abb Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Thu, 21 Apr 2022 13:27:43 +0000 Subject: [PATCH 02/10] Added initial dman test setup --- consensus/dman/actors_test.go | 2 +- consensus/dman/dman_test.go | 648 ++++++++++++++++++++++++++++++++ consensus/dman/internaltypes.go | 3 + 3 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 consensus/dman/dman_test.go diff --git a/consensus/dman/actors_test.go b/consensus/dman/actors_test.go index 88b955bd..8f6e40f3 100644 --- a/consensus/dman/actors_test.go +++ b/consensus/dman/actors_test.go @@ -286,7 +286,7 @@ func TestRootActor_download(t *testing.T) { defer ra.Close() trb.expect(tt.proxyCalls, tt.proxyReturns) ra.download(tt.args.b, false) - t.Log("waiting on download from RA2") + t.Log("waiting on download from RA") <-time.After(5 * time.Second) // allow some time for actors to do their thing }() }) diff --git a/consensus/dman/dman_test.go b/consensus/dman/dman_test.go new file mode 100644 index 00000000..8962b658 --- /dev/null +++ b/consensus/dman/dman_test.go @@ -0,0 +1,648 @@ +package dman + +import ( + "context" + "crypto/rand" + "errors" + "fmt" + "strconv" + "sync" + "testing" + + aobjs "github.com/MadBase/MadNet/application/objs" + "github.com/MadBase/MadNet/application/objs/uint256" + trie "github.com/MadBase/MadNet/badgerTrie" + "github.com/MadBase/MadNet/consensus/appmock" + "github.com/MadBase/MadNet/consensus/db" + "github.com/MadBase/MadNet/consensus/objs" + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/interfaces" + "github.com/MadBase/MadNet/logging" + "github.com/MadBase/MadNet/utils" + "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" +) + +type dmanTestProxy struct { + sync.Mutex + callIndex int + expectedCalls []testingProxyCall + returns [][]interface{} + skipCallCheck bool + db *db.Database + logger *logrus.Logger +} + +// assert struct `dmanTestProxy` implements `reqBusView` , `appmock.Application`, `databaseView` interfaces +var _ reqBusView = &dmanTestProxy{} +var _ appmock.Application = &dmanTestProxy{} +var _ databaseView = &dmanTestProxy{} + +//var _ typeProxyIface = &dmanTestProxy{} + +// implementation of reqBusView interface + +func (p *dmanTestProxy) RequestP2PGetPendingTx(ctx context.Context, txHashes [][]byte, opts ...grpc.CallOption) ([][]byte, error) { + defer func() { + p.callIndex++ + }() + // cType := pendingTxCall + p.Lock() + defer p.Unlock() + // if p.callIndex == len(p.expectedCalls) { + // panic(fmt.Sprintf("got unexpected call of type %s : expected calls %v", cType, p.expectedCalls)) + // } + // if p.expectedCalls[p.callIndex] != cType { + // panic(fmt.Sprintf("got unexpected call of type %s at index %v : expected calls %v", cType, p.callIndex, p.expectedCalls)) + // } + // if ctx == nil { + // panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) + // } + ret := [][]byte{make([]byte, constants.HashLen)} + // returnTuple := p.returns[p.callIndex] + // tx := returnTuple[0].([][]byte) + // err, ok := returnTuple[1].(error) + // if ok { + // return tx, err + // } + return ret, nil +} + +func (p *dmanTestProxy) RequestP2PGetMinedTxs(ctx context.Context, txHashes [][]byte, opts ...grpc.CallOption) ([][]byte, error) { + defer func() { + p.callIndex++ + }() + // cType := minedTxCall + p.Lock() + defer p.Unlock() + // if p.callIndex == len(p.expectedCalls) { + // panic(fmt.Sprintf("got unexpected call of type %s : expected calls %v", cType, p.expectedCalls)) + // } + // if p.expectedCalls[p.callIndex] != cType { + // panic(fmt.Sprintf("got unexpected call of type %s at index %v : expected calls %v", cType, p.callIndex, p.expectedCalls)) + // } + // if ctx == nil { + // panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) + // } + ret := [][]byte{make([]byte, constants.HashLen)} + // returnTuple := p.returns[p.callIndex] + // tx := returnTuple[0].([][]byte) + // err, ok := returnTuple[1].(error) + // if ok { + // return tx, err + // } + return ret, nil +} + +func (p *dmanTestProxy) RequestP2PGetBlockHeaders(ctx context.Context, blockNums []uint32, opts ...grpc.CallOption) ([]*objs.BlockHeader, error) { + defer func() { + p.callIndex++ + }() + // cType := blockHeaderCall + fmt.Println("RequestP2PGetBlockHeaders()") + p.Lock() + defer p.Unlock() + // if p.callIndex == len(p.expectedCalls) { + // panic(fmt.Sprintf("got unexpected call of type %s : expected calls %v, callIndex %v", cType, p.expectedCalls, p.callIndex)) + // } + // if p.expectedCalls[p.callIndex] != cType { + // panic(fmt.Sprintf("got unexpcted call of type %s at index %v : expected calls %v, callIndex %v", cType, p.callIndex, p.expectedCalls, p.callIndex)) + // } + // if ctx == nil { + // panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) + // } + + //bh := makeGoodBlock(t) + + // returnTuple := p.returns[p.callIndex] + // bh := returnTuple[0].([]*objs.BlockHeader) + // err, ok := returnTuple[1].(error) + // if ok { + // return bh, err + // } + return nil, errors.New("could not request block header from P2P") +} + +// implementation of databaseView interface + +func (p *dmanTestProxy) SetTxCacheItem(txn *badger.Txn, height uint32, txHash []byte, tx []byte) error { + fmt.Printf("SetTxCacheItem mocked. height: %v, txHash: %x\n", height, txHash) + return p.db.SetTxCacheItem(txn, height, txHash, tx) +} + +func (p *dmanTestProxy) GetTxCacheItem(txn *badger.Txn, height uint32, txHash []byte) ([]byte, error) { + fmt.Printf("GetTxCacheItem mocked. height: %v, txHash: %x\n", height, txHash) + return p.db.GetTxCacheItem(txn, height, txHash) +} + +func (p *dmanTestProxy) SetCommittedBlockHeader(txn *badger.Txn, v *objs.BlockHeader) error { + return p.db.SetCommittedBlockHeader(txn, v) +} + +func (p *dmanTestProxy) TxCacheDropBefore(txn *badger.Txn, beforeHeight uint32, maxKeys int) error { + return p.db.TxCacheDropBefore(txn, beforeHeight, maxKeys) +} + +// implementation of appmock.Application interface + +// //MockApplication is the the receiver for TxHandler interface +// type MockApplication struct { +// logger *logrus.Logger +// validValue *objs.Proposal +// MissingTxn bool +// } + +const ( + notImpl = "not implemented" +) + +// SetNextValidValue is defined on the interface object +func (p *dmanTestProxy) SetNextValidValue(vv *objs.Proposal) { + panic(notImpl) +} + +// ApplyState is defined on the interface object +func (p *dmanTestProxy) ApplyState(txn *badger.Txn, chainID, height uint32, txs []interfaces.Transaction) ([]byte, error) { + fmt.Printf("dmanTestProxy.ApplyState()\n") + //err := p.SetTxCacheItem() AddTxs(txn, 1, []interfaces.Transaction{tx}) + //assert.Nil(t, err) + return nil, nil +} + +//GetValidProposal is defined on the interface object +func (p *dmanTestProxy) GetValidProposal(txn *badger.Txn, chainID, height, maxBytes uint32) ([]interfaces.Transaction, []byte, error) { + return nil, nil, nil +} + +// PendingTxAdd is defined on the interface object +func (p *dmanTestProxy) PendingTxAdd(txn *badger.Txn, chainID, height uint32, txs []interfaces.Transaction) error { + return nil +} + +//IsValid is defined on the interface object +func (p *dmanTestProxy) IsValid(txn *badger.Txn, chainID uint32, height uint32, stateHash []byte, _ []interfaces.Transaction) (bool, error) { + return false, nil +} + +// MinedTxGet is defined on the interface object +func (p *dmanTestProxy) MinedTxGet(*badger.Txn, [][]byte) ([]interfaces.Transaction, [][]byte, error) { + return nil, nil, nil +} + +// PendingTxGet is defined on the interface object +func (p *dmanTestProxy) PendingTxGet(txn *badger.Txn, height uint32, txhashes [][]byte) ([]interfaces.Transaction, [][]byte, error) { + return nil, nil, nil +} + +//PendingTxContains is defined on the interface object +func (p *dmanTestProxy) PendingTxContains(txn *badger.Txn, height uint32, txHashes [][]byte) ([][]byte, error) { + return nil, nil +} + +// UnmarshalTx is defined on the interface object +func (p *dmanTestProxy) UnmarshalTx(v []byte) (interfaces.Transaction, error) { + tx := &aobjs.Tx{} + err := tx.UnmarshalBinary(v) + if err != nil { + utils.DebugTrace(p.logger, err) + return nil, err + } + return tx, nil +} + +// StoreSnapShotNode is defined on the interface object +func (p *dmanTestProxy) StoreSnapShotNode(txn *badger.Txn, batch []byte, root []byte, layer int) ([][]byte, int, []trie.LeafNode, error) { + panic(notImpl) +} + +// GetSnapShotNode is defined on the interface object +func (p *dmanTestProxy) GetSnapShotNode(txn *badger.Txn, height uint32, key []byte) ([]byte, error) { + panic(notImpl) +} + +// StoreSnapShotStateData is defined on the interface object +func (p *dmanTestProxy) StoreSnapShotStateData(txn *badger.Txn, key []byte, value []byte, data []byte) error { + panic(notImpl) +} + +// GetSnapShotStateData is defined on the interface object +func (p *dmanTestProxy) GetSnapShotStateData(txn *badger.Txn, key []byte) ([]byte, error) { + panic(notImpl) +} + +// FinalizeSnapShotRoot is defined on the interface object +func (p *dmanTestProxy) FinalizeSnapShotRoot(txn *badger.Txn, root []byte, height uint32) error { + panic(notImpl) +} + +// BeginSnapShotSync is defined on the interface object +func (p *dmanTestProxy) BeginSnapShotSync(txn *badger.Txn) error { + panic(notImpl) +} + +// FinalizeSync is defined on the interface object +func (p *dmanTestProxy) FinalizeSync(txn *badger.Txn) error { + panic(notImpl) +} + +// MockTransaction is defined on the interface object +type MockTransaction struct { + V []byte +} + +// TxHash is defined on the interface object +func (m *MockTransaction) TxHash() ([]byte, error) { + return crypto.Hasher(m.V), nil +} + +//MarshalBinary is defined on the interface object +func (m *MockTransaction) MarshalBinary() ([]byte, error) { + return m.V, nil +} + +//XXXIsTx is defined on the interface object +func (m *MockTransaction) XXXIsTx() {} + +func initDatabase(ctx context.Context, path string, inMemory bool) *badger.DB { + db, err := utils.OpenBadger(ctx.Done(), path, inMemory) + if err != nil { + panic(err) + } + return db +} + +func Test_DMan(t *testing.T) { + var p *dmanTestProxy = &dmanTestProxy{} + var dman *DMan = &DMan{} + dman.Init(p, p, p) + dman.Close() +} + +func Test_Get(t *testing.T) { + ctx := context.Background() + nodeCtx, cf := context.WithCancel(ctx) + defer cf() + + // Initialize consensus db: stores all state the consensus mechanism requires to work + rawConsensusDb := initDatabase(nodeCtx, "", true) + defer rawConsensusDb.Close() + + db := &db.Database{} + db.Init(rawConsensusDb) + + var p *dmanTestProxy = &dmanTestProxy{db: db} + + ra := &RootActor{} + err := ra.Init(logging.GetLogger("Test"), p) + if err != nil { + t.Fatal(err) + } + ra.Start() + defer ra.Close() + + var dman *DMan = &DMan{ + ra, + p, + p, + nil, + logging.GetLogger("Test"), + } + dman.Init(p, p, p) + defer dman.Close() + + dman.Start() + defer dman.Close() + + ownerSigner := testingOwner() + /*consumedUTXOs*/ _, tx := makeTxInitial(ownerSigner) + + hash, err := tx.TxHash() + assert.Nil(t, err) + binary, err := tx.MarshalBinary() + assert.Nil(t, err) + + txsToGet := make([][]byte, 0) + + // test + err = db.Update(func(txn *badger.Txn) error { + // bclaimsList, txHashListList, err := generateFullChain(1) + // if err != nil { + // t.Fatal(err) + // } + + // tx := interfaces.Transaction + // dman.appHandler.ApplyState(txn, 1, 1) + + // _, err = dman.appHandler.ApplyState(txn, 1, 1, []interfaces.Transaction{tx}) + // assert.Nil(t, err) + //assert.NotNil(t, stateHash) + + //err = dman.AddTxs(txn, 1, []interfaces.Transaction{tx}) + //assert.Nil(t, err) + + //db.SetTxCacheItem(txn, 1, hash, binary) + + err = dman.database.SetTxCacheItem(txn, 1, hash, binary) + assert.Nil(t, err) + //txsToGet := make([][]byte, 0) + txsToGet = append(txsToGet, hash) + //err = txn.Commit() + //assert.Nil(t, err) + + //dman.database.GetTxCacheItem( + + txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + binary2, err := tx.MarshalBinary() + assert.Nil(t, err) + assert.NotNil(t, txs) + assert.Equal(t, binary, binary2) + //assert.Len(t, txMissing, 0) + + return err + }) + + //dman.GetTxs() + + assert.Nil(t, err) + + err = db.View(func(txn *badger.Txn) error { + txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + binary2, err := tx.MarshalBinary() + assert.Nil(t, err) + assert.NotNil(t, txs) + assert.Equal(t, binary, binary2) + + // txs, txMissing, err := dman.GetTxs(txn, 1, 1, txsToGet) + // assert.Nil(t, err) + // assert.Len(t, txs, 1) + // assert.Len(t, txMissing, 0) + + // return err + + return err + }) + + assert.Nil(t, err) + + // test + // db.Update(func(txn *badger.Txn) error { + // txs, txMissing, err := dman.GetTxs(txn, 1, 1, make([][]byte, 0)) + // assert.Nil(t, err) + // assert.Len(t, txs, 1) + // assert.Len(t, txMissing, 0) + + // return err + // }) + +} + +func Test_Get2(t *testing.T) { + logger := logging.GetLogger("Test") + + ctx := context.Background() + nodeCtx, cf := context.WithCancel(ctx) + defer cf() + + // Initialize consensus db: stores all state the consensus mechanism requires to work + rawConsensusDb := initDatabase(nodeCtx, "", true) + defer rawConsensusDb.Close() + + db := &db.Database{} + db.Init(rawConsensusDb) + + var p *dmanTestProxy = &dmanTestProxy{ + db: db, + logger: logger, + } + + ra := &RootActor{} + err := ra.Init(logger, p) + if err != nil { + t.Fatal(err) + } + ra.Start() + defer ra.Close() + + var dman *DMan = &DMan{ + ra, + p, + p, + nil, + logger, + } + dman.Init(p, p, p) + defer dman.Close() + + dman.Start() + defer dman.Close() + + ownerSigner := testingOwner() + /*consumedUTXOs*/ _, tx := makeTxInitial(ownerSigner) + + hash, err := tx.TxHash() + assert.Nil(t, err) + binary, err := tx.MarshalBinary() + assert.Nil(t, err) + + txsToGet := make([][]byte, 0) + + // test + err = db.Update(func(txn *badger.Txn) error { + err = dman.database.SetTxCacheItem(txn, 1, hash, binary) + assert.Nil(t, err) + txsToGet = append(txsToGet, hash) + + txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + binary2, err := tx.MarshalBinary() + assert.Nil(t, err) + assert.NotNil(t, txs) + assert.Equal(t, binary, binary2) + + return err + }) + + assert.Nil(t, err) + + err = db.View(func(txn *badger.Txn) error { + txs, missing, err := dman.GetTxs(txn, 1, 1, txsToGet) + + assert.Nil(t, err) + assert.Len(t, txs, 1) + assert.Len(t, missing, 0) + binary2, err := txs[0].MarshalBinary() + assert.Nil(t, err) + assert.Equal(t, binary, binary2) + + return err + }) + + assert.Nil(t, err) + + err = db.View(func(txn *badger.Txn) error { + txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + binary2, err := tx.MarshalBinary() + assert.Nil(t, err) + assert.Len(t, txs, 1) + assert.Equal(t, binary, binary2) + + return err + }) + + assert.Nil(t, err) + +} + +func generateFullChain(length int) ([]*objs.BClaims, [][][]byte, error) { + chain := []*objs.BClaims{} + txHashes := [][][]byte{} + txhash := crypto.Hasher([]byte(strconv.Itoa(1))) + txHshLst := [][]byte{txhash} + txRoot, err := objs.MakeTxRoot(txHshLst) + if err != nil { + return nil, nil, err + } + txHashes = append(txHashes, txHshLst) + bclaims := &objs.BClaims{ + ChainID: 1, + Height: 1, + TxCount: 1, + PrevBlock: crypto.Hasher([]byte("foo")), + TxRoot: txRoot, + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + chain = append(chain, bclaims) + for i := 1; i < length; i++ { + bhsh, err := chain[i-1].BlockHash() + if err != nil { + return nil, nil, err + } + txhash := crypto.Hasher([]byte(strconv.Itoa(i))) + txHshLst := [][]byte{txhash} + txRoot, err := objs.MakeTxRoot(txHshLst) + if err != nil { + return nil, nil, err + } + txHashes = append(txHashes, txHshLst) + bclaims := &objs.BClaims{ + ChainID: 1, + Height: uint32(len(chain) + 1), + TxCount: 1, + PrevBlock: bhsh, + TxRoot: txRoot, + StateRoot: chain[i-1].StateRoot, + HeaderRoot: chain[i-1].HeaderRoot, + } + chain = append(chain, bclaims) + } + return chain, txHashes, nil +} + +func testingOwner() aobjs.Signer { + signer := &crypto.Secp256k1Signer{} + err := signer.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + panic(err) + } + return signer +} + +func accountFromSigner(s aobjs.Signer) []byte { + pubk, err := s.Pubkey() + if err != nil { + panic(err) + } + return crypto.GetAccount(pubk) +} + +func makeVS(ownerSigner aobjs.Signer) *aobjs.TXOut { + cid := uint32(2) + //val := uint32(1) + val := uint256.One() + + ownerAcct := accountFromSigner(ownerSigner) + owner := &aobjs.ValueStoreOwner{} + owner.New(ownerAcct, constants.CurveSecp256k1) + + vsp := &aobjs.VSPreImage{ + ChainID: cid, + Value: val, + Owner: owner, + Fee: uint256.Zero(), + } + vs := &aobjs.ValueStore{ + VSPreImage: vsp, + TxHash: make([]byte, constants.HashLen), + } + utxInputs := &aobjs.TXOut{} + err := utxInputs.NewValueStore(vs) + if err != nil { + panic(err) + } + return utxInputs +} + +func makeVSTXIn(ownerSigner aobjs.Signer, txHash []byte) (*aobjs.TXOut, *aobjs.TXIn) { + vs := makeVS(ownerSigner) + vss, err := vs.ValueStore() + if err != nil { + panic(err) + } + if txHash == nil { + txHash = make([]byte, constants.HashLen) + rand.Read(txHash) + } + vss.TxHash = txHash + + txIn, err := vss.MakeTxIn() + if err != nil { + panic(err) + } + return vs, txIn +} + +func makeTxInitial(ownerSigner aobjs.Signer) (aobjs.Vout, *aobjs.Tx) { + consumedUTXOs := aobjs.Vout{} + txInputs := []*aobjs.TXIn{} + for i := 0; i < 2; i++ { + utxo, txin := makeVSTXIn(ownerSigner, nil) + consumedUTXOs = append(consumedUTXOs, utxo) + txInputs = append(txInputs, txin) + } + generatedUTXOs := aobjs.Vout{} + for i := 0; i < 2; i++ { + generatedUTXOs = append(generatedUTXOs, makeVS(ownerSigner)) + } + err := generatedUTXOs.SetTxOutIdx() + if err != nil { + panic(err) + } + txfee := uint256.Zero() + tx := &aobjs.Tx{ + Vin: txInputs, + Vout: generatedUTXOs, + Fee: txfee, + } + err = tx.SetTxHash() + if err != nil { + panic(err) + } + for i := 0; i < 2; i++ { + vs, err := consumedUTXOs[i].ValueStore() + if err != nil { + panic(err) + } + err = vs.Sign(tx.Vin[i], ownerSigner) + if err != nil { + panic(err) + } + } + return consumedUTXOs, tx +} diff --git a/consensus/dman/internaltypes.go b/consensus/dman/internaltypes.go index e507576d..af2d87e5 100644 --- a/consensus/dman/internaltypes.go +++ b/consensus/dman/internaltypes.go @@ -74,6 +74,9 @@ type typeProxy struct { databaseView } +// assert struct typeProxy implements typeProxyIface interface +var _ typeProxyIface = &typeProxy{} + type TxDownloadRequest struct { TxHash []byte `json:"tx_hash,omitempty"` Dtype DownloadType `json:"dtype,omitempty"` From 170916e44e428693980fa9fa66495d99a54f5976 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Mon, 25 Apr 2022 15:14:07 +0000 Subject: [PATCH 03/10] More tests --- consensus/dman/actors.go | 1 - consensus/dman/actors_test.go | 46 +++++- consensus/dman/dman_test.go | 295 ++++++++++++++++++++-------------- 3 files changed, 220 insertions(+), 122 deletions(-) diff --git a/consensus/dman/actors.go b/consensus/dman/actors.go index 4dca2c4c..398b1a2b 100644 --- a/consensus/dman/actors.go +++ b/consensus/dman/actors.go @@ -77,7 +77,6 @@ func (a *RootActor) Close() { }) } -// TODO verify blockheader cache is being cleaned func (a *RootActor) FlushCacheToDisk(txn *badger.Txn, height uint32) error { txList, txHashList := a.txc.GetHeight(height + 1) for i := 0; i < len(txList); i++ { diff --git a/consensus/dman/actors_test.go b/consensus/dman/actors_test.go index 8f6e40f3..8e975d27 100644 --- a/consensus/dman/actors_test.go +++ b/consensus/dman/actors_test.go @@ -15,6 +15,7 @@ import ( "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/logging" "github.com/dgraph-io/badger/v2" + "github.com/stretchr/testify/assert" "google.golang.org/grpc" ) @@ -287,7 +288,7 @@ func TestRootActor_download(t *testing.T) { trb.expect(tt.proxyCalls, tt.proxyReturns) ra.download(tt.args.b, false) t.Log("waiting on download from RA") - <-time.After(5 * time.Second) // allow some time for actors to do their thing + <-time.After(5 * time.Second) // allow some time for actors to do their work }() }) if tt.args.check { @@ -303,6 +304,49 @@ func TestRootActor_download(t *testing.T) { } } +func TestRootActor_FlushCacheToDisk(t *testing.T) { + trb := &testingProxy{} + ra := &RootActor{} + tlog := logging.GetLogger("Test") + err := ra.Init(tlog, trb) + if err != nil { + t.Fatal(err) + } + ra.Start() + defer ra.Close() + + // db + ctx := context.Background() + nodeCtx, cf := context.WithCancel(ctx) + defer cf() + + // Initialize consensus db: stores all state the consensus mechanism requires to work + rawConsensusDb := initDatabase(nodeCtx, "", true) + defer rawConsensusDb.Close() + + trb.callIndex = 0 + trb.expectedCalls = []testingProxyCall{blockHeaderCall} + trb.returns = append([][]interface{}{}, []interface{}{makeGoodBlock(t), nil}) + + dlReq := NewBlockHeaderDownloadRequest(1, 1, BlockHeaderRequest) + ra.download(dlReq, false) + + t.Log("waiting on download from RA") + <-time.After(5 * time.Second) // allow some time for actors to do their work + + err = rawConsensusDb.Update(func(txn *badger.Txn) error { + err = ra.FlushCacheToDisk(txn, 1) + assert.Nil(t, err) + + // todo: check with Troy + assert.False(t, ra.bhc.Contains(1)) + + return err + }) + + assert.Nil(t, err) +} + func makeGoodBlock(t *testing.T) []*objs.BlockHeader { bclaimsList, txHashListList, err := generateChain() if err != nil { diff --git a/consensus/dman/dman_test.go b/consensus/dman/dman_test.go index 8962b658..223f8013 100644 --- a/consensus/dman/dman_test.go +++ b/consensus/dman/dman_test.go @@ -49,6 +49,7 @@ func (p *dmanTestProxy) RequestP2PGetPendingTx(ctx context.Context, txHashes [][ defer func() { p.callIndex++ }() + fmt.Println("RequestP2PGetPendingTx()") // cType := pendingTxCall p.Lock() defer p.Unlock() @@ -75,6 +76,7 @@ func (p *dmanTestProxy) RequestP2PGetMinedTxs(ctx context.Context, txHashes [][] defer func() { p.callIndex++ }() + fmt.Println("RequestP2PGetMinedTxs()") // cType := minedTxCall p.Lock() defer p.Unlock() @@ -266,6 +268,8 @@ func (m *MockTransaction) MarshalBinary() ([]byte, error) { //XXXIsTx is defined on the interface object func (m *MockTransaction) XXXIsTx() {} +// test setup + func initDatabase(ctx context.Context, path string, inMemory bool) *badger.DB { db, err := utils.OpenBadger(ctx.Done(), path, inMemory) if err != nil { @@ -274,175 +278,231 @@ func initDatabase(ctx context.Context, path string, inMemory bool) *badger.DB { return db } -func Test_DMan(t *testing.T) { - var p *dmanTestProxy = &dmanTestProxy{} - var dman *DMan = &DMan{} - dman.Init(p, p, p) - dman.Close() -} +func setupDmanTests(t *testing.T) (testProxy *dmanTestProxy, dman *DMan, ownerSigner aobjs.Signer, closeFn func()) { + logger := logging.GetLogger("Test") + deferables := make([]func(), 0) + + closeFn = func() { + // iterate in reverse order because deferables behave like a stack: + // the last added deferable should be the first executed + totalDeferables := len(deferables) + for i := totalDeferables - 1; i >= 0; i-- { + deferables[i]() + } + } -func Test_Get(t *testing.T) { ctx := context.Background() nodeCtx, cf := context.WithCancel(ctx) - defer cf() + deferables = append(deferables, cf) // Initialize consensus db: stores all state the consensus mechanism requires to work rawConsensusDb := initDatabase(nodeCtx, "", true) - defer rawConsensusDb.Close() + var closeDB func() = func() { + err := rawConsensusDb.Close() + if err != nil { + panic(fmt.Errorf("error closing rawConsensusDb: %v", err)) + } + } + deferables = append(deferables, closeDB) db := &db.Database{} db.Init(rawConsensusDb) - var p *dmanTestProxy = &dmanTestProxy{db: db} + testProxy = &dmanTestProxy{ + db: db, + logger: logger, + } ra := &RootActor{} - err := ra.Init(logging.GetLogger("Test"), p) + err := ra.Init(logger, testProxy) if err != nil { + closeFn() t.Fatal(err) + return } ra.Start() - defer ra.Close() + deferables = append(deferables, ra.Close) - var dman *DMan = &DMan{ + dman = &DMan{ ra, - p, - p, + testProxy, + testProxy, nil, - logging.GetLogger("Test"), + logger, } - dman.Init(p, p, p) - defer dman.Close() + dman.Init(testProxy, testProxy, testProxy) + deferables = append(deferables, dman.Close) dman.Start() - defer dman.Close() - ownerSigner := testingOwner() - /*consumedUTXOs*/ _, tx := makeTxInitial(ownerSigner) + ownerSigner = testingOwner() + + return +} + +func Test_DMan(t *testing.T) { + var p *dmanTestProxy = &dmanTestProxy{} + var dman *DMan = &DMan{} + dman.Init(p, p, p) + dman.Close() +} + +func Test_GetNonExistent(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() + + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) hash, err := tx.TxHash() assert.Nil(t, err) - binary, err := tx.MarshalBinary() - assert.Nil(t, err) - txsToGet := make([][]byte, 0) + err = testProxy.db.View(func(txn *badger.Txn) error { + tx2Binary, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.NotNil(t, err) + assert.Nil(t, tx2Binary) - // test - err = db.Update(func(txn *badger.Txn) error { - // bclaimsList, txHashListList, err := generateFullChain(1) - // if err != nil { - // t.Fatal(err) - // } + return nil + }) + + assert.Nil(t, err) - // tx := interfaces.Transaction - // dman.appHandler.ApplyState(txn, 1, 1) +} + +func Test_SetAndGet(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() - // _, err = dman.appHandler.ApplyState(txn, 1, 1, []interfaces.Transaction{tx}) - // assert.Nil(t, err) - //assert.NotNil(t, stateHash) + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) - //err = dman.AddTxs(txn, 1, []interfaces.Transaction{tx}) - //assert.Nil(t, err) + hash, err := tx.TxHash() + assert.Nil(t, err) + binary, err := tx.MarshalBinary() + assert.Nil(t, err) - //db.SetTxCacheItem(txn, 1, hash, binary) + txsToGet := make([][]byte, 0) + // test + err = testProxy.db.Update(func(txn *badger.Txn) error { err = dman.database.SetTxCacheItem(txn, 1, hash, binary) assert.Nil(t, err) - //txsToGet := make([][]byte, 0) txsToGet = append(txsToGet, hash) - //err = txn.Commit() - //assert.Nil(t, err) - //dman.database.GetTxCacheItem( + tx2Binary, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + assert.NotNil(t, tx2Binary) - txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + tx2 := &aobjs.Tx{} + err = tx2.UnmarshalBinary(tx2Binary) assert.Nil(t, err) - binary2, err := tx.MarshalBinary() + + binary2, err := tx2.MarshalBinary() assert.Nil(t, err) - assert.NotNil(t, txs) assert.Equal(t, binary, binary2) - //assert.Len(t, txMissing, 0) - return err }) - //dman.GetTxs() - assert.Nil(t, err) - err = db.View(func(txn *badger.Txn) error { - txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + err = testProxy.db.View(func(txn *badger.Txn) error { + // read through dman.GetTxs + txs, missing, err := dman.GetTxs(txn, 1, 1, txsToGet) assert.Nil(t, err) - binary2, err := tx.MarshalBinary() + assert.Len(t, txs, 1) + assert.Len(t, missing, 0) + + binary2, err := txs[0].MarshalBinary() assert.Nil(t, err) - assert.NotNil(t, txs) assert.Equal(t, binary, binary2) - // txs, txMissing, err := dman.GetTxs(txn, 1, 1, txsToGet) - // assert.Nil(t, err) - // assert.Len(t, txs, 1) - // assert.Len(t, txMissing, 0) + // read through dman.database.GetTxCacheItem + tx2Binary, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + assert.NotNil(t, tx2Binary) - // return err + tx2 := &aobjs.Tx{} + err = tx2.UnmarshalBinary(tx2Binary) + assert.Nil(t, err) + + binary2, err = tx2.MarshalBinary() + assert.Nil(t, err) + assert.Equal(t, binary, binary2) + assert.Equal(t, binary, tx2Binary) + assert.Equal(t, binary2, tx2Binary) return err }) assert.Nil(t, err) +} + +func Test_FlushCacheToDisk(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() + + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) + + hash, err := tx.TxHash() + assert.Nil(t, err) + binary, err := tx.MarshalBinary() + assert.Nil(t, err) + // test - // db.Update(func(txn *badger.Txn) error { - // txs, txMissing, err := dman.GetTxs(txn, 1, 1, make([][]byte, 0)) - // assert.Nil(t, err) - // assert.Len(t, txs, 1) - // assert.Len(t, txMissing, 0) + err = testProxy.db.Update(func(txn *badger.Txn) error { + err = dman.database.SetTxCacheItem(txn, 1, hash, binary) + assert.Nil(t, err) + + err := dman.FlushCacheToDisk(txn, 1) + assert.Nil(t, err) - // return err - // }) + // todo: check with Troy + assert.False(t, dman.downloadActor.bhc.Contains(1)) + return err + }) + + assert.Nil(t, err) } -func Test_Get2(t *testing.T) { - logger := logging.GetLogger("Test") +func Test_CleanCache(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() - ctx := context.Background() - nodeCtx, cf := context.WithCancel(ctx) - defer cf() + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) - // Initialize consensus db: stores all state the consensus mechanism requires to work - rawConsensusDb := initDatabase(nodeCtx, "", true) - defer rawConsensusDb.Close() + hash, err := tx.TxHash() + assert.Nil(t, err) + binary, err := tx.MarshalBinary() + assert.Nil(t, err) - db := &db.Database{} - db.Init(rawConsensusDb) + // test + err = testProxy.db.Update(func(txn *badger.Txn) error { + err = dman.database.SetTxCacheItem(txn, 1, hash, binary) + assert.Nil(t, err) - var p *dmanTestProxy = &dmanTestProxy{ - db: db, - logger: logger, - } + err := dman.CleanCache(txn, 1) + assert.Nil(t, err) - ra := &RootActor{} - err := ra.Init(logger, p) - if err != nil { - t.Fatal(err) - } - ra.Start() - defer ra.Close() + // todo: check with Troy + assert.False(t, dman.downloadActor.bhc.Contains(1)) - var dman *DMan = &DMan{ - ra, - p, - p, - nil, - logger, - } - dman.Init(p, p, p) - defer dman.Close() + return err + }) - dman.Start() - defer dman.Close() + assert.Nil(t, err) +} - ownerSigner := testingOwner() - /*consumedUTXOs*/ _, tx := makeTxInitial(ownerSigner) +func Test_AddTxs(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() + + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) + var txs []interfaces.Transaction = []interfaces.Transaction{tx} hash, err := tx.TxHash() assert.Nil(t, err) @@ -450,53 +510,48 @@ func Test_Get2(t *testing.T) { assert.Nil(t, err) txsToGet := make([][]byte, 0) + txsToGet = append(txsToGet, hash) // test - err = db.Update(func(txn *badger.Txn) error { - err = dman.database.SetTxCacheItem(txn, 1, hash, binary) + err = testProxy.db.Update(func(txn *badger.Txn) error { + err := dman.AddTxs(txn, 1, txs) assert.Nil(t, err) - txsToGet = append(txsToGet, hash) - - txs, err := dman.database.GetTxCacheItem(txn, 1, hash) - assert.Nil(t, err) - binary2, err := tx.MarshalBinary() - assert.Nil(t, err) - assert.NotNil(t, txs) - assert.Equal(t, binary, binary2) return err }) assert.Nil(t, err) - err = db.View(func(txn *badger.Txn) error { + err = testProxy.db.View(func(txn *badger.Txn) error { + // read through dman.GetTxs txs, missing, err := dman.GetTxs(txn, 1, 1, txsToGet) - assert.Nil(t, err) assert.Len(t, txs, 1) assert.Len(t, missing, 0) + binary2, err := txs[0].MarshalBinary() assert.Nil(t, err) assert.Equal(t, binary, binary2) - return err - }) - - assert.Nil(t, err) + // read through dman.database.GetTxCacheItem + tx2Binary, err := dman.database.GetTxCacheItem(txn, 1, hash) + assert.Nil(t, err) + assert.NotNil(t, tx2Binary) - err = db.View(func(txn *badger.Txn) error { - txs, err := dman.database.GetTxCacheItem(txn, 1, hash) + tx2 := &aobjs.Tx{} + err = tx2.UnmarshalBinary(tx2Binary) assert.Nil(t, err) - binary2, err := tx.MarshalBinary() + + binary2, err = tx2.MarshalBinary() assert.Nil(t, err) - assert.Len(t, txs, 1) assert.Equal(t, binary, binary2) + assert.Equal(t, binary, tx2Binary) + assert.Equal(t, binary2, tx2Binary) return err }) assert.Nil(t, err) - } func generateFullChain(length int) ([]*objs.BClaims, [][][]byte, error) { From 028448a545621775cbcd6e5b840d4ec3d3e9fa5f Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Thu, 28 Apr 2022 12:48:28 +0000 Subject: [PATCH 04/10] DMan tests passing --- consensus/dman/dman_test.go | 86 ++++++++++++++++++++++++++++++++++--- middleware/peer.go | 9 ++-- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/consensus/dman/dman_test.go b/consensus/dman/dman_test.go index 223f8013..57628247 100644 --- a/consensus/dman/dman_test.go +++ b/consensus/dman/dman_test.go @@ -8,6 +8,7 @@ import ( "strconv" "sync" "testing" + "time" aobjs "github.com/MadBase/MadNet/application/objs" "github.com/MadBase/MadNet/application/objs/uint256" @@ -34,6 +35,7 @@ type dmanTestProxy struct { skipCallCheck bool db *db.Database logger *logrus.Logger + testTx *aobjs.Tx } // assert struct `dmanTestProxy` implements `reqBusView` , `appmock.Application`, `databaseView` interfaces @@ -62,7 +64,22 @@ func (p *dmanTestProxy) RequestP2PGetPendingTx(ctx context.Context, txHashes [][ // if ctx == nil { // panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) // } - ret := [][]byte{make([]byte, constants.HashLen)} + + //ret := [][]byte{make([]byte, constants.HashLen)} + + bin, err := p.testTx.MarshalBinary() + if err != nil { + panic(fmt.Errorf("RequestP2PGetPendingTx() error tx.MarshalBinary(): %v", err)) + } + + hash, err := p.testTx.TxHash() + if err != nil { + panic(fmt.Errorf("RequestP2PGetPendingTx() error tx.TxHash(): %v", err)) + } + fmt.Printf("RequestP2PGetPendingTx returning %v", hash) + + ret := [][]byte{bin} + // returnTuple := p.returns[p.callIndex] // tx := returnTuple[0].([][]byte) // err, ok := returnTuple[1].(error) @@ -89,7 +106,22 @@ func (p *dmanTestProxy) RequestP2PGetMinedTxs(ctx context.Context, txHashes [][] // if ctx == nil { // panic(fmt.Sprintf("ctx was nil in test mock object of call type %s", cType)) // } - ret := [][]byte{make([]byte, constants.HashLen)} + + //ret := [][]byte{make([]byte, constants.HashLen)} + + bin, err := p.testTx.MarshalBinary() + if err != nil { + panic(fmt.Errorf("RequestP2PGetMinedTxs() error tx.MarshalBinary(): %v", err)) + } + + hash, err := p.testTx.TxHash() + if err != nil { + panic(fmt.Errorf("RequestP2PGetMinedTxs() error tx.TxHash(): %v", err)) + } + fmt.Printf("RequestP2PGetMinedTxs returning %v", hash) + + ret := [][]byte{bin} + // returnTuple := p.returns[p.callIndex] // tx := returnTuple[0].([][]byte) // err, ok := returnTuple[1].(error) @@ -340,7 +372,7 @@ func setupDmanTests(t *testing.T) (testProxy *dmanTestProxy, dman *DMan, ownerSi return } -func Test_DMan(t *testing.T) { +func Test_DManProxy(t *testing.T) { var p *dmanTestProxy = &dmanTestProxy{} var dman *DMan = &DMan{} dman.Init(p, p, p) @@ -458,7 +490,6 @@ func Test_FlushCacheToDisk(t *testing.T) { err := dman.FlushCacheToDisk(txn, 1) assert.Nil(t, err) - // todo: check with Troy assert.False(t, dman.downloadActor.bhc.Contains(1)) return err @@ -487,7 +518,6 @@ func Test_CleanCache(t *testing.T) { err := dman.CleanCache(txn, 1) assert.Nil(t, err) - // todo: check with Troy assert.False(t, dman.downloadActor.bhc.Contains(1)) return err @@ -512,7 +542,7 @@ func Test_AddTxs(t *testing.T) { txsToGet := make([][]byte, 0) txsToGet = append(txsToGet, hash) - // test + // add Txs err = testProxy.db.Update(func(txn *badger.Txn) error { err := dman.AddTxs(txn, 1, txs) assert.Nil(t, err) @@ -554,6 +584,50 @@ func Test_AddTxs(t *testing.T) { assert.Nil(t, err) } +func Test_DownloadTxs(t *testing.T) { + testProxy, dman, ownerSigner, closeFn := setupDmanTests(t) + defer closeFn() + + assert.False(t, dman.downloadActor.bhc.Contains(1)) + + /*consumedUTXOs*/ + _, tx := makeTxInitial(ownerSigner) + var txs []interfaces.Transaction = []interfaces.Transaction{tx} + + hash, err := tx.TxHash() + assert.Nil(t, err) + testProxy.testTx = tx + + txsToGet := make([][]byte, 0) + txsToGet = append(txsToGet, hash) + + assert.False(t, dman.downloadActor.txc.Contains(hash)) + + // add Txs + err = testProxy.db.Update(func(txn *badger.Txn) error { + err := dman.AddTxs(txn, 1, txs) + assert.Nil(t, err) + + return err + }) + + assert.Nil(t, err) + + assert.False(t, dman.downloadActor.txc.Contains(hash)) + assert.False(t, dman.downloadActor.bhc.Contains(1)) + + // download the Txs + dman.DownloadTxs(1, 1, txsToGet) + + // wait some time for actors to download Txs + <-time.After(5 * time.Second) + + t.Logf("expecting hash: %v", hash) + + assert.True(t, dman.downloadActor.txc.Contains(hash)) + assert.False(t, dman.downloadActor.bhc.Contains(1)) +} + func generateFullChain(length int) ([]*objs.BClaims, [][][]byte, error) { chain := []*objs.BClaims{} txHashes := [][][]byte{} diff --git a/middleware/peer.go b/middleware/peer.go index a08d2983..61d66fe3 100644 --- a/middleware/peer.go +++ b/middleware/peer.go @@ -38,9 +38,12 @@ func (opt *PeerCallOption) setPeer(p PeerClient) { // NewPeerInterceptor is a function that builds a grpc.CallOption that will // return a peer ref to the caller func NewPeerInterceptor() *PeerCallOption { - opt := &PeerCallOption{EmptyCallOption: &grpc.EmptyCallOption{}, Peer: func() PeerClient { - return peerClient{} - }} + opt := &PeerCallOption{ + EmptyCallOption: &grpc.EmptyCallOption{}, + Peer: func() PeerClient { + return peerClient{} + }, + } return opt } From 7a2e671e3a89aa8100fd8bf0c90b4cb7b114fd02 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Fri, 29 Apr 2022 19:02:42 +0000 Subject: [PATCH 05/10] Testing admin Handler --- consensus/admin/handlers.go | 2 +- consensus/admin/handlers_test.go | 252 +++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 consensus/admin/handlers_test.go diff --git a/consensus/admin/handlers.go b/consensus/admin/handlers.go index f0fc752e..867949ad 100644 --- a/consensus/admin/handlers.go +++ b/consensus/admin/handlers.go @@ -382,7 +382,7 @@ func (ah *Handlers) AddPrivateKey(pk []byte, curveSpec constants.CurveSpec) erro return nil } -// GetPrivK returns an decrypted private key from an EthDKG run to the caller +// GetPrivK returns a decrypted private key from an EthDKG run to the caller func (ah *Handlers) GetPrivK(name []byte) ([]byte, error) { var privk []byte err := ah.database.View(func(txn *badger.Txn) error { diff --git a/consensus/admin/handlers_test.go b/consensus/admin/handlers_test.go new file mode 100644 index 00000000..1b9c7aa0 --- /dev/null +++ b/consensus/admin/handlers_test.go @@ -0,0 +1,252 @@ +package admin + +import ( + "context" + "fmt" + "testing" + + aobjs "github.com/MadBase/MadNet/application/objs" + trie "github.com/MadBase/MadNet/badgerTrie" + "github.com/MadBase/MadNet/config" + "github.com/MadBase/MadNet/consensus/appmock" + "github.com/MadBase/MadNet/consensus/db" + "github.com/MadBase/MadNet/consensus/objs" + "github.com/MadBase/MadNet/constants" + mncrypto "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/dynamics" + "github.com/MadBase/MadNet/interfaces" + "github.com/MadBase/MadNet/ipc" + "github.com/MadBase/MadNet/logging" + "github.com/MadBase/MadNet/utils" + "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +type ahTestProxy struct { + logger *logrus.Logger + db *db.Database + ah *Handlers + secretKey []byte +} + +var _ appmock.Application = &ahTestProxy{} + +const ( + notImpl = "not implemented" +) + +// SetNextValidValue is defined on the interface object +func (p *ahTestProxy) SetNextValidValue(vv *objs.Proposal) { + panic(notImpl) +} + +// ApplyState is defined on the interface object +func (p *ahTestProxy) ApplyState(txn *badger.Txn, chainID, height uint32, txs []interfaces.Transaction) ([]byte, error) { + fmt.Printf("ahTestProxy.ApplyState()\n") + //err := p.SetTxCacheItem() AddTxs(txn, 1, []interfaces.Transaction{tx}) + //assert.Nil(t, err) + return nil, nil +} + +//GetValidProposal is defined on the interface object +func (p *ahTestProxy) GetValidProposal(txn *badger.Txn, chainID, height, maxBytes uint32) ([]interfaces.Transaction, []byte, error) { + return nil, nil, nil +} + +// PendingTxAdd is defined on the interface object +func (p *ahTestProxy) PendingTxAdd(txn *badger.Txn, chainID, height uint32, txs []interfaces.Transaction) error { + return nil +} + +//IsValid is defined on the interface object +func (p *ahTestProxy) IsValid(txn *badger.Txn, chainID uint32, height uint32, stateHash []byte, _ []interfaces.Transaction) (bool, error) { + return false, nil +} + +// MinedTxGet is defined on the interface object +func (p *ahTestProxy) MinedTxGet(*badger.Txn, [][]byte) ([]interfaces.Transaction, [][]byte, error) { + return nil, nil, nil +} + +// PendingTxGet is defined on the interface object +func (p *ahTestProxy) PendingTxGet(txn *badger.Txn, height uint32, txhashes [][]byte) ([]interfaces.Transaction, [][]byte, error) { + return nil, nil, nil +} + +//PendingTxContains is defined on the interface object +func (p *ahTestProxy) PendingTxContains(txn *badger.Txn, height uint32, txHashes [][]byte) ([][]byte, error) { + return nil, nil +} + +// UnmarshalTx is defined on the interface object +func (p *ahTestProxy) UnmarshalTx(v []byte) (interfaces.Transaction, error) { + tx := &aobjs.Tx{} + err := tx.UnmarshalBinary(v) + if err != nil { + utils.DebugTrace(p.logger, err) + return nil, err + } + return tx, nil +} + +// StoreSnapShotNode is defined on the interface object +func (p *ahTestProxy) StoreSnapShotNode(txn *badger.Txn, batch []byte, root []byte, layer int) ([][]byte, int, []trie.LeafNode, error) { + panic(notImpl) +} + +// GetSnapShotNode is defined on the interface object +func (p *ahTestProxy) GetSnapShotNode(txn *badger.Txn, height uint32, key []byte) ([]byte, error) { + panic(notImpl) +} + +// StoreSnapShotStateData is defined on the interface object +func (p *ahTestProxy) StoreSnapShotStateData(txn *badger.Txn, key []byte, value []byte, data []byte) error { + panic(notImpl) +} + +// GetSnapShotStateData is defined on the interface object +func (p *ahTestProxy) GetSnapShotStateData(txn *badger.Txn, key []byte) ([]byte, error) { + panic(notImpl) +} + +// FinalizeSnapShotRoot is defined on the interface object +func (p *ahTestProxy) FinalizeSnapShotRoot(txn *badger.Txn, root []byte, height uint32) error { + panic(notImpl) +} + +// BeginSnapShotSync is defined on the interface object +func (p *ahTestProxy) BeginSnapShotSync(txn *badger.Txn) error { + panic(notImpl) +} + +// FinalizeSync is defined on the interface object +func (p *ahTestProxy) FinalizeSync(txn *badger.Txn) error { + panic(notImpl) +} + +// MockTransaction is defined on the interface object +type MockTransaction struct { + V []byte +} + +// TxHash is defined on the interface object +func (m *MockTransaction) TxHash() ([]byte, error) { + return mncrypto.Hasher(m.V), nil +} + +//MarshalBinary is defined on the interface object +func (m *MockTransaction) MarshalBinary() ([]byte, error) { + return m.V, nil +} + +//XXXIsTx is defined on the interface object +func (m *MockTransaction) XXXIsTx() {} + +// setupAHTests +func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { + logger := logging.GetLogger("Test") + deferables := make([]func(), 0) + + closeFn = func() { + // iterate in reverse order because deferables behave like a stack: + // the last added deferable should be the first executed + totalDeferables := len(deferables) + for i := totalDeferables - 1; i >= 0; i-- { + deferables[i]() + } + } + + var chainID uint32 = 1337 + ctx := context.Background() + nodeCtx, cf := context.WithCancel(ctx) + deferables = append(deferables, cf) + + // Initialize consensus db: stores all state the consensus mechanism requires to work + rawConsensusDb, err := utils.OpenBadger(nodeCtx.Done(), "", true) + assert.Nil(t, err) + var closeDB func() = func() { + err := rawConsensusDb.Close() + if err != nil { + panic(fmt.Errorf("error closing rawConsensusDb: %v", err)) + } + } + deferables = append(deferables, closeDB) + + db := &db.Database{} + db.Init(rawConsensusDb) + + secretKey := mncrypto.Hasher([]byte("someSuperFancySecretThatWillBeHashed")) + + testProxy = &ahTestProxy{ + logger: logger, + db: db, + secretKey: secretKey, + } + + ethPubKey := []byte("b904C0A2d203Ceb2B518055f116064666C028240") + storage := &dynamics.Storage{} + + ipcServer := ipc.NewServer(config.Configuration.Firewalld.SocketFile) + deferables = append(deferables, ipcServer.Close) + + testProxy.ah = &Handlers{} + testProxy.ah.Init(chainID, db, secretKey, testProxy, ethPubKey, storage, ipcServer) + deferables = append(deferables, testProxy.ah.Close) + + return +} + +func TestAdminHandlerSetup(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + err := ahTestProxy.db.View(func(txn *badger.Txn) error { + txHashes := make([][]byte, 0) + txHashes = append(txHashes, []byte("aaa")) + pendingTxs, err := ahTestProxy.PendingTxContains(txn, 1, txHashes) + assert.Nil(t, err) + assert.Empty(t, pendingTxs) + + return err + }) + assert.Nil(t, err) +} + +func TestAdminHandler_GetKey(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + key, err := ahTestProxy.ah.GetKey([]byte("aaa")) + assert.Nil(t, err) + assert.NotNil(t, key) + // todo: this was unexpected just by looking at the API docs + // todo: should this be renamed from GetKey to GetSecretKeyHash ? + assert.Equal(t, key, ahTestProxy.secretKey) + +} + +func TestAdminHandler_DontGetPrivK(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + key, err := ahTestProxy.ah.GetPrivK([]byte("a random name 123")) + assert.NotNil(t, err) + assert.Nil(t, key) +} + +func TestAdminHandler_AddPrivateKey_CurveSecp256k1(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + err := ahTestProxy.ah.AddPrivateKey([]byte("a random private key 123"), constants.CurveSecp256k1) + assert.Nil(t, err) +} + +func TestAdminHandler_AddPrivateKey_CurveBN256Eth(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + err := ahTestProxy.ah.AddPrivateKey([]byte("a random private key 123"), constants.CurveBN256Eth) + assert.Nil(t, err) +} From 5591bad6ae4f67e63490517c0b5c963eaa303735 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Mon, 9 May 2022 18:56:20 +0000 Subject: [PATCH 06/10] Added more tests to admin.Handler --- consensus/admin/handlers_test.go | 274 ++++++++++++++++++++++++++++++- consensus/db/db.go | 5 +- consensus/synchronizer.go | 4 + 3 files changed, 280 insertions(+), 3 deletions(-) diff --git a/consensus/admin/handlers_test.go b/consensus/admin/handlers_test.go index 1b9c7aa0..84081f43 100644 --- a/consensus/admin/handlers_test.go +++ b/consensus/admin/handlers_test.go @@ -3,22 +3,29 @@ package admin import ( "context" "fmt" + "math/big" + "strconv" + "sync" "testing" aobjs "github.com/MadBase/MadNet/application/objs" trie "github.com/MadBase/MadNet/badgerTrie" + "github.com/MadBase/MadNet/blockchain/objects" "github.com/MadBase/MadNet/config" "github.com/MadBase/MadNet/consensus/appmock" "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/crypto" mncrypto "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/crypto/bn256" "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/ipc" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" + "github.com/ethereum/go-ethereum/common" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) @@ -194,6 +201,27 @@ func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { testProxy.ah.Init(chainID, db, secretKey, testProxy, ethPubKey, storage, ipcServer) deferables = append(deferables, testProxy.ah.Close) + assert.False(t, testProxy.ah.IsInitialized()) + + // start goroutine to emulate Synchronizer.adminInteruptLoop() + closeCh := make(chan struct{}) + deferables = append(deferables, func() { close(closeCh) }) + synchronizer := &synchronizerMock{} + + go func(closeChan chan struct{}) { + //defer s.wg.Done() + defer func() { fmt.Println("Stopping AdminInterupt loop") }() + fmt.Println("Starting AdminInterupt loop") + for { + select { + case testProxy.ah.ReceiveLock <- synchronizer: + continue + case <-closeChan: + return + } + } + }(closeCh) + return } @@ -239,7 +267,7 @@ func TestAdminHandler_AddPrivateKey_CurveSecp256k1(t *testing.T) { ahTestProxy, closeFn := setupAHTests(t) defer closeFn() - err := ahTestProxy.ah.AddPrivateKey([]byte("a random private key 123"), constants.CurveSecp256k1) + err := ahTestProxy.ah.AddPrivateKey([]byte("a random 32byte private key 1234"), constants.CurveSecp256k1) assert.Nil(t, err) } @@ -250,3 +278,247 @@ func TestAdminHandler_AddPrivateKey_CurveBN256Eth(t *testing.T) { err := ahTestProxy.ah.AddPrivateKey([]byte("a random private key 123"), constants.CurveBN256Eth) assert.Nil(t, err) } + +func TestAdminHandler_Sinchronization(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + assert.False(t, ahTestProxy.ah.IsSynchronized()) + + ahTestProxy.ah.SetSynchronized(true) + assert.True(t, ahTestProxy.ah.IsSynchronized()) + + ahTestProxy.ah.SetSynchronized(false) + assert.False(t, ahTestProxy.ah.IsSynchronized()) +} + +func TestAdminHandler_AddValidatorSet(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + vs := generateValidatorSet(t) + + err := ahTestProxy.ah.AddValidatorSet(vs) + assert.Nil(t, err, err) +} + +func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { + ahTestProxy, closeFn := setupAHTests(t) + defer closeFn() + + ahTestProxy.ah.RegisterSnapshotCallback(func(bh *objs.BlockHeader) error { + t.Logf("SnapshotCallback is being called!") + ahTestProxy.logger.Printf("SnapshotCallback is being called 2!") + //panic("sss") + return nil + }) + + // add validator set + vs := generateValidatorSet(t) + err := ahTestProxy.ah.AddValidatorSet(vs) + assert.Nil(t, err, err) + + bhs := makeGoodBlock(t, 32) + + //err := ahTestProxy.ah.AddSnapshot(bh, false) + //assert.Nil(t, err) + + for i := 0; i < 31; i++ { + err := ahTestProxy.db.Update(func(txn *badger.Txn) error { + return ahTestProxy.ah.database.SetBroadcastBlockHeader(txn, bhs[i]) + }) + + assert.Nil(t, err) + } + + err = ahTestProxy.ah.AddSnapshot(bhs[31], false) + assert.Nil(t, err) +} + +func makeGoodBlock(t *testing.T, nBlocks int) []*objs.BlockHeader { + bclaimsList, txHashListList, err := generateChain(nBlocks) + if err != nil { + t.Fatal(err) + } + + bhs := make([]*objs.BlockHeader, 0) + + gk := crypto.BNGroupSigner{} + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < nBlocks; i++ { + bclaims := bclaimsList[i] + bhsh, err := bclaims.BlockHash() + if err != nil { + t.Fatal(err) + } + + sig, err := gk.Sign(bhsh) + if err != nil { + t.Fatal(err) + } + bh := &objs.BlockHeader{ + BClaims: bclaims, + SigGroup: sig, + TxHshLst: txHashListList[i], + } + bhs = append(bhs, bh) + } + + return bhs +} + +func generateChain(nBlocks int) ([]*objs.BClaims, [][][]byte, error) { + chain := []*objs.BClaims{} + txHashes := [][][]byte{} + + for i := 0; i < nBlocks; i++ { + + txhash := crypto.Hasher([]byte(strconv.Itoa(i + 1))) + txHshLst := [][]byte{txhash} + txRoot, err := objs.MakeTxRoot(txHshLst) + if err != nil { + return nil, nil, err + } + txHashes = append(txHashes, txHshLst) + + prevBlockHash := crypto.Hasher([]byte("foo")) + + if i > 0 { + prevBlockHash, err = chain[i-1].BlockHash() + if err != nil { + panic(fmt.Errorf("could not create prevBlockHash: %v\n", err)) + } + } + + bclaims := &objs.BClaims{ + ChainID: 1, + Height: uint32(i) + 1, + TxCount: 1, + PrevBlock: prevBlockHash, + TxRoot: txRoot, + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + chain = append(chain, bclaims) + } + + return chain, txHashes, nil +} + +func generateValidatorSet(t *testing.T) *objs.ValidatorSet { + gpkj1, ok := big.NewInt(0).SetString("14395602319113363333690669395961581081803242358678131578916981232954633806960", 10) + assert.True(t, ok) + gpkj2, ok := big.NewInt(0).SetString("300089735810954642595088127891607498572672898349379085034409445552605516765", 10) + assert.True(t, ok) + gpkj3, ok := big.NewInt(0).SetString("17169409825226096532229555694191340178889298261881998623204757401596570351688", 10) + assert.True(t, ok) + gpkj4, ok := big.NewInt(0).SetString("19780380227412019371988923760536598779715024137904246485146692590642474692882", 10) + assert.True(t, ok) + + v1 := objects.Validator{ + Account: common.HexToAddress("0x9AC1c9afBAec85278679fF75Ef109217f26b1417"), + Index: 1, + SharedKey: [4]*big.Int{ + gpkj1, + gpkj2, + gpkj3, + gpkj4, + }, + } + + gpkj1, ok = big.NewInt(0).SetString("21154017404198718862920160130737623556546602199694661996869957208062851500379", 10) + assert.True(t, ok) + gpkj2, ok = big.NewInt(0).SetString("19389833000731437962153734187923001234830293448701992540723746507685386979412", 10) + assert.True(t, ok) + gpkj3, ok = big.NewInt(0).SetString("21289029302611008572663530729853170393569891172031986702208364730022339833735", 10) + assert.True(t, ok) + gpkj4, ok = big.NewInt(0).SetString("15926764275937493411567546154328577890519582979565228998979506880914326856186", 10) + assert.True(t, ok) + + v2 := objects.Validator{ + Account: common.HexToAddress("0x615695C4a4D6a60830e5fca4901FbA099DF26271"), + Index: 2, + SharedKey: [4]*big.Int{ + gpkj1, + gpkj2, + gpkj3, + gpkj4, + }, + } + + gpkj1, ok = big.NewInt(0).SetString("15079629603150363557558188402860791995814736941924946256968815481986722866449", 10) + assert.True(t, ok) + gpkj2, ok = big.NewInt(0).SetString("11164680325282976674805760467491699367894125557056167854003650409966070344792", 10) + assert.True(t, ok) + gpkj3, ok = big.NewInt(0).SetString("18616624374737795490811424594534628399519274885945803292205658067710235197668", 10) + assert.True(t, ok) + gpkj4, ok = big.NewInt(0).SetString("4331613963825409904165282575933135091483251249365224295595121580000486079984", 10) + assert.True(t, ok) + + v3 := objects.Validator{ + Account: common.HexToAddress("0x63a6627b79813A7A43829490C4cE409254f64177"), + Index: 3, + SharedKey: [4]*big.Int{ + gpkj1, + gpkj2, + gpkj3, + gpkj4, + }, + } + + gpkj1, ok = big.NewInt(0).SetString("10875965504600753744265546216544158224793678652818595873355677460529088515116", 10) + assert.True(t, ok) + gpkj2, ok = big.NewInt(0).SetString("7912658035712558991777053184829906144303269569825235765302768068512975453162", 10) + assert.True(t, ok) + gpkj3, ok = big.NewInt(0).SetString("11324169944454120842956077363729540506362078469024985744551121054724657909930", 10) + assert.True(t, ok) + gpkj4, ok = big.NewInt(0).SetString("11005450895245397587287710270721947847266013997080161834700568409163476112947", 10) + assert.True(t, ok) + + v4 := objects.Validator{ + Account: common.HexToAddress("0x16564cF3e880d9F5d09909F51b922941EbBbC24d"), + Index: 4, + SharedKey: [4]*big.Int{ + gpkj1, + gpkj2, + gpkj3, + gpkj4, + }, + } + + validators := []objects.Validator{v1, v2, v3, v4} + ptrGroupKey := [4]*big.Int{ + v1.SharedKey[0], + v1.SharedKey[1], + v1.SharedKey[2], + v1.SharedKey[3], + } + groupKey, err := bn256.MarshalG2Big(ptrGroupKey) + assert.Nil(t, err) + vs := &objs.ValidatorSet{ + GroupKey: groupKey, + Validators: make([]*objs.Validator, len(validators)), + NotBefore: 0, + } + + for _, validator := range validators { + v := &objs.Validator{ + VAddr: validator.Account.Bytes(), + GroupShare: groupKey, + } + vs.Validators[validator.Index-1] = v + } + + return vs +} + +type synchronizerMock struct { + sync.Mutex +} + +// assert Synchronizer struct implements interfaces.Lockable interface +var _ interfaces.Lockable = &synchronizerMock{} diff --git a/consensus/db/db.go b/consensus/db/db.go index 26dba386..2d0cd97a 100644 --- a/consensus/db/db.go +++ b/consensus/db/db.go @@ -2,6 +2,7 @@ package db import ( "context" + "fmt" "sync" "github.com/MadBase/MadNet/constants/dbprefix" @@ -1699,7 +1700,7 @@ func (pni *PendingLeafIter) Close() { func (db *Database) SetSafeToProceed(txn *badger.Txn, height uint32, isSafe bool) error { if height%constants.EpochLength != 1 { - panic("The height must be mod 1 epoch length") + panic(fmt.Errorf("the height must be mod 1 epoch length. height: %v\n", height)) } key := &objs.SafeToProceedKey{Prefix: dbprefix.PrefixSafeToProceed(), Height: height} k, err := key.MarshalBinary() @@ -1714,7 +1715,7 @@ func (db *Database) SetSafeToProceed(txn *badger.Txn, height uint32, isSafe bool func (db *Database) GetSafeToProceed(txn *badger.Txn, height uint32) (bool, error) { if height%constants.EpochLength != 1 { - panic("The height must be mod 1 epoch length") + panic(fmt.Errorf("The height must be mod 1 epoch length. height: %v\n", height)) } key := &objs.SafeToProceedKey{Prefix: dbprefix.PrefixSafeToProceed(), Height: height} k, err := key.MarshalBinary() diff --git a/consensus/synchronizer.go b/consensus/synchronizer.go index 74a25845..56667404 100644 --- a/consensus/synchronizer.go +++ b/consensus/synchronizer.go @@ -14,6 +14,7 @@ import ( "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/peering" "github.com/dgraph-io/badger/v2" @@ -216,6 +217,9 @@ type Synchronizer struct { storage dynamics.StorageGetter } +// assert Synchronizer struct implements interfaces.Lockable interface +var _ interfaces.Lockable = &Synchronizer{} + // Init initializes the struct func (s *Synchronizer) Init(cdb *db.Database, mdb *badger.DB, tdb *badger.DB, gc *gossip.Client, gh *gossip.Handlers, ep *evidence.Pool, eng *lstate.Engine, app *application.Application, ah *admin.Handlers, pman *peering.PeerManager, storage dynamics.StorageGetter) { s.logger = logging.GetLogger(constants.LoggerConsensus) From 3c450d53eb6449fa8d053fadbff693f2cec24043 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Wed, 11 May 2022 20:02:14 +0000 Subject: [PATCH 07/10] RegisterSnapshotCallback tested! --- consensus/admin/handlers_test.go | 129 +++++++++++++++++++++++++------ consensus/db/rawdb.go | 2 +- 2 files changed, 105 insertions(+), 26 deletions(-) diff --git a/consensus/admin/handlers_test.go b/consensus/admin/handlers_test.go index 84081f43..75a431eb 100644 --- a/consensus/admin/handlers_test.go +++ b/consensus/admin/handlers_test.go @@ -2,13 +2,16 @@ package admin import ( "context" + "encoding/hex" "fmt" "math/big" "strconv" "sync" "testing" + "time" aobjs "github.com/MadBase/MadNet/application/objs" + utxo "github.com/MadBase/MadNet/application/utxohandler" trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/blockchain/objects" "github.com/MadBase/MadNet/config" @@ -31,10 +34,12 @@ import ( ) type ahTestProxy struct { - logger *logrus.Logger - db *db.Database - ah *Handlers - secretKey []byte + logger *logrus.Logger + db *db.Database + ah *Handlers + secretKey []byte + rawConsensusDb *badger.DB + utxoHandler *utxo.UTXOHandler } var _ appmock.Application = &ahTestProxy{} @@ -50,10 +55,7 @@ func (p *ahTestProxy) SetNextValidValue(vv *objs.Proposal) { // ApplyState is defined on the interface object func (p *ahTestProxy) ApplyState(txn *badger.Txn, chainID, height uint32, txs []interfaces.Transaction) ([]byte, error) { - fmt.Printf("ahTestProxy.ApplyState()\n") - //err := p.SetTxCacheItem() AddTxs(txn, 1, []interfaces.Transaction{tx}) - //assert.Nil(t, err) - return nil, nil + return p.utxoHandler.ApplyState(txn, aobjs.TxVec{}, 1) } //GetValidProposal is defined on the interface object @@ -183,12 +185,20 @@ func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { db := &db.Database{} db.Init(rawConsensusDb) + hndlr := utxo.NewUTXOHandler(rawConsensusDb) + err = hndlr.Init(1) + if err != nil { + t.Fatal(err) + } + secretKey := mncrypto.Hasher([]byte("someSuperFancySecretThatWillBeHashed")) testProxy = &ahTestProxy{ - logger: logger, - db: db, - secretKey: secretKey, + logger: logger, + db: db, + secretKey: secretKey, + rawConsensusDb: rawConsensusDb, + utxoHandler: hndlr, } ethPubKey := []byte("b904C0A2d203Ceb2B518055f116064666C028240") @@ -299,14 +309,17 @@ func TestAdminHandler_AddValidatorSet(t *testing.T) { vs := generateValidatorSet(t) err := ahTestProxy.ah.AddValidatorSet(vs) - assert.Nil(t, err, err) + assert.Nil(t, err) } func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { ahTestProxy, closeFn := setupAHTests(t) defer closeFn() + var xxx = false + didRunCallback := &xxx ahTestProxy.ah.RegisterSnapshotCallback(func(bh *objs.BlockHeader) error { + *didRunCallback = true t.Logf("SnapshotCallback is being called!") ahTestProxy.logger.Printf("SnapshotCallback is being called 2!") //panic("sss") @@ -318,25 +331,82 @@ func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { err := ahTestProxy.ah.AddValidatorSet(vs) assert.Nil(t, err, err) - bhs := makeGoodBlock(t, 32) - //err := ahTestProxy.ah.AddSnapshot(bh, false) //assert.Nil(t, err) - for i := 0; i < 31; i++ { - err := ahTestProxy.db.Update(func(txn *badger.Txn) error { - return ahTestProxy.ah.database.SetBroadcastBlockHeader(txn, bhs[i]) - }) + bhs := ahTestProxy.makeGoodBlock(t, 32) + + err = ahTestProxy.db.Update(func(txn *badger.Txn) error { + addrBytes, err := hex.DecodeString("9AC1c9afBAec85278679fF75Ef109217f26b1417") + assert.Nil(t, err) + ownState := &objs.OwnState{ + VAddr: addrBytes, + SyncToBH: bhs[0], + MaxBHSeen: bhs[0], + CanonicalSnapShot: bhs[0], + PendingSnapShot: bhs[0], + } + return ahTestProxy.db.SetOwnState(txn, ownState) + }) + assert.Nil(t, err) + + for i := 0; i < 32; i++ { + //t.Logf("iteration i: %v, block: %#v\n", i, bhs[i].BClaims) + binary, err := bhs[i].MarshalBinary() + assert.Nil(t, err) + //t.Logf("binary: %x", binary) + bht := &objs.BlockHeader{} + err = bht.UnmarshalBinary(binary) + assert.Nil(t, err) + + if i == 0 { + err = ahTestProxy.db.Update(func(txn *badger.Txn) error { + err := ahTestProxy.db.SetSnapshotBlockHeader(txn, bhs[i]) + assert.Nil(t, err) + + return err + }) + assert.Nil(t, err) + } else { + err = ahTestProxy.db.Update(func(txn *badger.Txn) error { + err := ahTestProxy.db.SetBroadcastBlockHeader(txn, bhs[i]) + assert.Nil(t, err) + + _, err = ahTestProxy.ah.database.GetBroadcastBlockHeader(txn) + assert.Nil(t, err) + //t.Logf("got bh: %#v", bh.BClaims) + + return err + }) + assert.Nil(t, err) + + } + + // err = ahTestProxy.db.View(func(txn *badger.Txn) error { + // bh, err := ahTestProxy.ah.database.GetBroadcastBlockHeader(txn) + // assert.Nil(t, err) + // t.Logf("got bh: %#v", bh.BClaims) + + // return err + // }) assert.Nil(t, err) + + //ahTestProxy.rawConsensusDb. + + //<-time.After(2 * time.Second) } - err = ahTestProxy.ah.AddSnapshot(bhs[31], false) - assert.Nil(t, err) + // err = ahTestProxy.ah.AddSnapshot(bhs[31], true) + // assert.Nil(t, err) + + <-time.After(5 * time.Second) + + assert.True(t, *didRunCallback) } -func makeGoodBlock(t *testing.T, nBlocks int) []*objs.BlockHeader { - bclaimsList, txHashListList, err := generateChain(nBlocks) +func (ah *ahTestProxy) makeGoodBlock(t *testing.T, nBlocks int) []*objs.BlockHeader { + bclaimsList, txHashListList, err := ah.generateChain(nBlocks) if err != nil { t.Fatal(err) } @@ -371,7 +441,7 @@ func makeGoodBlock(t *testing.T, nBlocks int) []*objs.BlockHeader { return bhs } -func generateChain(nBlocks int) ([]*objs.BClaims, [][][]byte, error) { +func (ah *ahTestProxy) generateChain(nBlocks int) ([]*objs.BClaims, [][][]byte, error) { chain := []*objs.BClaims{} txHashes := [][][]byte{} @@ -394,14 +464,23 @@ func generateChain(nBlocks int) ([]*objs.BClaims, [][][]byte, error) { } } + var stateRoot []byte + err = ah.db.Update(func(txn *badger.Txn) error { + stateRoot, err = ah.ApplyState(txn, 1, uint32(i)+1, nil) + return err + }) + if err != nil || stateRoot == nil { + panic(err) + } + bclaims := &objs.BClaims{ ChainID: 1, Height: uint32(i) + 1, TxCount: 1, PrevBlock: prevBlockHash, TxRoot: txRoot, - StateRoot: crypto.Hasher([]byte("")), - HeaderRoot: crypto.Hasher([]byte("")), + StateRoot: stateRoot, + HeaderRoot: crypto.Hasher([]byte("header root")), } chain = append(chain, bclaims) } diff --git a/consensus/db/rawdb.go b/consensus/db/rawdb.go index ad031f6b..670a2988 100644 --- a/consensus/db/rawdb.go +++ b/consensus/db/rawdb.go @@ -82,7 +82,7 @@ func (db *rawDataBase) subscribeToPrefix(ctx context.Context, prefix []byte, cb fn2 := func() { err := db.db.Subscribe(ctx, fn, prefix) if err != nil && err != context.Canceled { - db.logger.Warnf("terminating db subscription for prefix: %v", prefix) + db.logger.Warnf("terminating db subscription for prefix: %v. err: %v", prefix, err) } } go fn2() From bfc42790bda3f53b5e157a4145a02d0382a46ef7 Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Wed, 11 May 2022 20:17:24 +0000 Subject: [PATCH 08/10] Fixed test mocking --- consensus/admin/handlers_test.go | 3 +-- consensus/dman/dman_test.go | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/consensus/admin/handlers_test.go b/consensus/admin/handlers_test.go index 75a431eb..92f009a9 100644 --- a/consensus/admin/handlers_test.go +++ b/consensus/admin/handlers_test.go @@ -15,7 +15,6 @@ import ( trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/blockchain/objects" "github.com/MadBase/MadNet/config" - "github.com/MadBase/MadNet/consensus/appmock" "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" @@ -42,7 +41,7 @@ type ahTestProxy struct { utxoHandler *utxo.UTXOHandler } -var _ appmock.Application = &ahTestProxy{} +var _ interfaces.Application = &ahTestProxy{} const ( notImpl = "not implemented" diff --git a/consensus/dman/dman_test.go b/consensus/dman/dman_test.go index 57628247..862966ad 100644 --- a/consensus/dman/dman_test.go +++ b/consensus/dman/dman_test.go @@ -13,7 +13,6 @@ import ( aobjs "github.com/MadBase/MadNet/application/objs" "github.com/MadBase/MadNet/application/objs/uint256" trie "github.com/MadBase/MadNet/badgerTrie" - "github.com/MadBase/MadNet/consensus/appmock" "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" @@ -38,9 +37,9 @@ type dmanTestProxy struct { testTx *aobjs.Tx } -// assert struct `dmanTestProxy` implements `reqBusView` , `appmock.Application`, `databaseView` interfaces +// assert struct `dmanTestProxy` implements `reqBusView` , `interfaces.Application`, `databaseView` interfaces var _ reqBusView = &dmanTestProxy{} -var _ appmock.Application = &dmanTestProxy{} +var _ interfaces.Application = &dmanTestProxy{} var _ databaseView = &dmanTestProxy{} //var _ typeProxyIface = &dmanTestProxy{} From 5808b163ee042702c5a229c8e257732dfbd064cf Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Thu, 12 May 2022 19:07:04 +0000 Subject: [PATCH 09/10] Added couple more checks to Handler tests and cleanups --- consensus/admin/handlers.go | 22 ------------ consensus/admin/handlers_test.go | 50 ++++++++------------------ consensus/dman/actors.go | 35 ------------------- consensus/dman/dman_test.go | 60 +++----------------------------- 4 files changed, 19 insertions(+), 148 deletions(-) diff --git a/consensus/admin/handlers.go b/consensus/admin/handlers.go index 14dc5cc4..ddf46ae5 100644 --- a/consensus/admin/handlers.go +++ b/consensus/admin/handlers.go @@ -222,28 +222,6 @@ func (ah *Handlers) AddSnapshot(bh *objs.BlockHeader, safeToProceedConsensus boo return nil } -// UpdateDynamicStorage updates dynamic storage values. -func (ah *Handlers) UpdateDynamicStorage(txn *badger.Txn, key, value string, epoch uint32) error { - mutex, ok := ah.getLock() - if !ok { - return nil - } - mutex.Lock() - defer mutex.Unlock() - - update, err := dynamics.NewUpdate(key, value, epoch) - if err != nil { - utils.DebugTrace(ah.logger, err) - return err - } - err = ah.storage.UpdateStorage(txn, update) - if err != nil { - utils.DebugTrace(ah.logger, err) - return err - } - return nil -} - // IsInitialized returns if the database has been initialized yet func (ah *Handlers) IsInitialized() bool { ah.RLock() diff --git a/consensus/admin/handlers_test.go b/consensus/admin/handlers_test.go index 92f009a9..2773680d 100644 --- a/consensus/admin/handlers_test.go +++ b/consensus/admin/handlers_test.go @@ -19,7 +19,6 @@ import ( "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" - mncrypto "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/crypto/bn256" "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/interfaces" @@ -140,7 +139,7 @@ type MockTransaction struct { // TxHash is defined on the interface object func (m *MockTransaction) TxHash() ([]byte, error) { - return mncrypto.Hasher(m.V), nil + return crypto.Hasher(m.V), nil } //MarshalBinary is defined on the interface object @@ -190,7 +189,7 @@ func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { t.Fatal(err) } - secretKey := mncrypto.Hasher([]byte("someSuperFancySecretThatWillBeHashed")) + secretKey := crypto.Hasher([]byte("someSuperFancySecretThatWillBeHashed")) testProxy = &ahTestProxy{ logger: logger, @@ -218,7 +217,6 @@ func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { synchronizer := &synchronizerMock{} go func(closeChan chan struct{}) { - //defer s.wg.Done() defer func() { fmt.Println("Stopping AdminInterupt loop") }() fmt.Println("Starting AdminInterupt loop") for { @@ -231,6 +229,11 @@ func setupAHTests(t *testing.T) (testProxy *ahTestProxy, closeFn func()) { } }(closeCh) + // start goroutine to emulate Handler.InitializationMonitor() + closeChInitializationMonitor := make(chan struct{}) + deferables = append(deferables, func() { close(closeChInitializationMonitor) }) + go testProxy.ah.InitializationMonitor(closeChInitializationMonitor) + return } @@ -314,14 +317,11 @@ func TestAdminHandler_AddValidatorSet(t *testing.T) { func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { ahTestProxy, closeFn := setupAHTests(t) defer closeFn() - var xxx = false - didRunCallback := &xxx + var didRunCallback bool = false ahTestProxy.ah.RegisterSnapshotCallback(func(bh *objs.BlockHeader) error { - *didRunCallback = true - t.Logf("SnapshotCallback is being called!") - ahTestProxy.logger.Printf("SnapshotCallback is being called 2!") - //panic("sss") + didRunCallback = true + ahTestProxy.logger.Printf("SnapshotCallback is being called!") return nil }) @@ -330,11 +330,9 @@ func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { err := ahTestProxy.ah.AddValidatorSet(vs) assert.Nil(t, err, err) - //err := ahTestProxy.ah.AddSnapshot(bh, false) - //assert.Nil(t, err) - bhs := ahTestProxy.makeGoodBlock(t, 32) + // add own state with custom validator address err = ahTestProxy.db.Update(func(txn *badger.Txn) error { addrBytes, err := hex.DecodeString("9AC1c9afBAec85278679fF75Ef109217f26b1417") assert.Nil(t, err) @@ -350,10 +348,9 @@ func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { assert.Nil(t, err) for i := 0; i < 32; i++ { - //t.Logf("iteration i: %v, block: %#v\n", i, bhs[i].BClaims) binary, err := bhs[i].MarshalBinary() assert.Nil(t, err) - //t.Logf("binary: %x", binary) + bht := &objs.BlockHeader{} err = bht.UnmarshalBinary(binary) assert.Nil(t, err) @@ -373,35 +370,18 @@ func TestAdminHandler_RegisterSnapshotCallback(t *testing.T) { _, err = ahTestProxy.ah.database.GetBroadcastBlockHeader(txn) assert.Nil(t, err) - //t.Logf("got bh: %#v", bh.BClaims) return err }) assert.Nil(t, err) - } - // err = ahTestProxy.db.View(func(txn *badger.Txn) error { - // bh, err := ahTestProxy.ah.database.GetBroadcastBlockHeader(txn) - // assert.Nil(t, err) - // t.Logf("got bh: %#v", bh.BClaims) - - // return err - // }) - assert.Nil(t, err) - - //ahTestProxy.rawConsensusDb. - - //<-time.After(2 * time.Second) } - // err = ahTestProxy.ah.AddSnapshot(bhs[31], true) - // assert.Nil(t, err) - - <-time.After(5 * time.Second) - - assert.True(t, *didRunCallback) + <-time.After(3 * time.Second) + assert.True(t, didRunCallback) + assert.True(t, ahTestProxy.ah.IsInitialized()) } func (ah *ahTestProxy) makeGoodBlock(t *testing.T, nBlocks int) []*objs.BlockHeader { diff --git a/consensus/dman/actors.go b/consensus/dman/actors.go index 398b1a2b..f33103e3 100644 --- a/consensus/dman/actors.go +++ b/consensus/dman/actors.go @@ -127,20 +127,16 @@ func (a *RootActor) DownloadBlockHeader(height, round uint32) { } func (a *RootActor) download(b DownloadRequest, retry bool) { - a.logger.Infof("RA got download(). downloadRequest: %#v, retry: %#v, ", b, retry) select { case <-a.closeChan: - a.logger.Infof("RA got download() <-a.closeChan") return default: - a.logger.Infof("RA got download() default") a.wg.Add(1) go a.doDownload(b, retry) } } func (a *RootActor) doDownload(b DownloadRequest, retry bool) { - a.logger.Infof("RA got doDownload(). downloadRequest: %#v, retry: %#v, ", b, retry) defer a.wg.Done() switch b.DownloadType() { case PendingTxRequest, MinedTxRequest: @@ -244,16 +240,13 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { a.reqs[b.Identifier()] = true return true }() - a.logger.Infof("RA got doDownload() BlockHeaderRequest: b: %#v, retry: %v, ok: %v", b, retry, ok) if !ok { return } select { case <-a.closeChan: - a.logger.Infof("RA got doDownload() BlockHeaderRequest <-a.closeChan") return case a.dispatchQ <- b: - a.logger.Infof("RA got doDownload() BlockHeaderRequest a.dispatchQ <- b") a.await(b, retry) } default: @@ -262,13 +255,10 @@ func (a *RootActor) doDownload(b DownloadRequest, retry bool) { } func (a *RootActor) await(req DownloadRequest, retry bool) { - a.logger.Info("RA got await()") select { case <-a.closeChan: - a.logger.Infof("RA got await() <-a.closeChan. req: %#v", req) return case resp := <-req.ResponseChan(): - a.logger.Infof("RA got await() resp := <-req.ResponseChan(). resp: %#v, req: %#v", resp, req) if resp == nil { return } @@ -300,7 +290,6 @@ func (a *RootActor) await(req DownloadRequest, retry bool) { } case BlockHeaderRequest: r := resp.(*BlockHeaderDownloadResponse) - a.logger.Infof("RA got await() BlockHeaderRequest. resp: %#v, req: %#v, r: %#v", resp, req, r) if r.Err != nil { utils.DebugTrace(a.logger, r.Err) if retry { @@ -310,13 +299,11 @@ func (a *RootActor) await(req DownloadRequest, retry bool) { } ok := func() bool { if err := a.bhc.Add(r.BH); err != nil { - a.logger.Warnf("error adding BH to cache: %v", err) utils.DebugTrace(a.logger, err) return false } return true }() - a.logger.Infof("RA got await() BlockHeaderRequest. ok: %v", ok) if ok { return } @@ -369,11 +356,9 @@ func (a *blockActor) getHeight() uint32 { } func (a *blockActor) run() { - a.Logger.Info("BA got run()") for { select { case <-a.closeChan: - a.Logger.Info("BA got run() <-a.closeChan") return case req := <-a.WorkQ: ok := func() bool { @@ -385,7 +370,6 @@ func (a *blockActor) run() { } return true }() - a.Logger.Infof("BA got run() req := <-a.WorkQ | ok: %v, req: %#v", ok, req) if !ok { continue } @@ -395,7 +379,6 @@ func (a *blockActor) run() { } func (a *blockActor) await(req DownloadRequest) { - a.Logger.Info("BA got await()") var subReq DownloadRequest switch req.DownloadType() { case PendingTxRequest, MinedTxRequest: @@ -408,24 +391,19 @@ func (a *blockActor) await(req DownloadRequest) { } case BlockHeaderRequest: reqTyped := req.(*BlockHeaderDownloadRequest) - a.Logger.Infof("BA got run() BlockHeaderRequest | reqTyped: %v", reqTyped) subReq = NewBlockHeaderDownloadRequest(reqTyped.Height, reqTyped.Round, reqTyped.Dtype) select { case <-a.closeChan: - a.Logger.Infof("BA got run() BlockHeaderRequest <-a.closeChan") return case a.dispatchQ <- subReq: - a.Logger.Infof("BA got run() BlockHeaderRequest a.dispatchQ <- subReq") } default: panic(fmt.Sprintf("req download type not found: %v", req.DownloadType())) } select { case <-a.closeChan: - a.Logger.Infof("BA got run() <-a.closeChan") return case resp := <-subReq.ResponseChan(): - a.Logger.Infof("BA got run() resp := <-subReq.ResponseChan() | resp: %#v", resp) if resp == nil { close(req.ResponseChan()) return @@ -438,17 +416,14 @@ func (a *blockActor) await(req DownloadRequest) { } return true }() - a.Logger.Infof("BA got run() resp := <-subReq.ResponseChan() | ok: %v", ok) if !ok { close(req.ResponseChan()) return } select { case <-a.closeChan: - a.Logger.Infof("BA got run() last <-a.closeChan") return case req.ResponseChan() <- resp: - a.Logger.Infof("BA got run() last req.ResponseChan() <- resp") } } } @@ -496,14 +471,11 @@ func (a *downloadActor) start() { } func (a *downloadActor) run() { - a.Logger.Info("downloadActor got run()") for { select { case <-a.closeChan: - a.Logger.Info("downloadActor got run() <-a.closeChan") return case req := <-a.WorkQ: - a.Logger.Infof("downloadActor got run() req := <-a.WorkQ. req: %#v", req) switch req.DownloadType() { case PendingTxRequest: select { @@ -522,9 +494,7 @@ func (a *downloadActor) run() { case BlockHeaderRequest: select { case a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest): - a.Logger.Infof("downloadActor got run() BlockHeaderRequest. a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest)") default: - a.Logger.Infof("downloadActor got run() BlockHeaderRequest. default") a.bha.start() a.BlockDispatchQ <- req.(*BlockHeaderDownloadRequest) } @@ -708,12 +678,10 @@ func (a *blockHeaderDownloadActor) start() { } func (a *blockHeaderDownloadActor) run() { - a.Logger.Info("blockHeaderDownloadActor got run()") for { select { case <-time.After(10 * time.Second): a.Lock() - a.Logger.Infof("blockHeaderDownloadActor got run() <-time.After(10 * time.Second). a.numWorkers: %v", a.numWorkers) if a.numWorkers > 1 { a.numWorkers-- @@ -722,10 +690,8 @@ func (a *blockHeaderDownloadActor) run() { } a.Unlock() case <-a.closeChan: - a.Logger.Info("blockHeaderDownloadActor got run() <-a.closeChan") return case reqOrig := <-a.WorkQ: - a.Logger.Infof("blockHeaderDownloadActor got run() reqOrig := <-a.WorkQ. reqOrig: %#v", reqOrig) bh, err := func(req *BlockHeaderDownloadRequest) (*objs.BlockHeader, error) { opts := []grpc.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(backoffAmount*time.Millisecond, .1)), @@ -745,7 +711,6 @@ func (a *blockHeaderDownloadActor) run() { } return bhLst[0], nil }(reqOrig) - a.Logger.Infof("blockHeaderDownloadActor got run() reqOrig := <-a.WorkQ. bh: %#v, err: %v", bh, err) reqOrig.ResponseChan() <- NewBlockHeaderDownloadResponse(reqOrig, bh, BlockHeaderRequest, err) } } diff --git a/consensus/dman/dman_test.go b/consensus/dman/dman_test.go index 862966ad..26051e66 100644 --- a/consensus/dman/dman_test.go +++ b/consensus/dman/dman_test.go @@ -5,7 +5,6 @@ import ( "crypto/rand" "errors" "fmt" - "strconv" "sync" "testing" "time" @@ -28,13 +27,10 @@ import ( type dmanTestProxy struct { sync.Mutex - callIndex int - expectedCalls []testingProxyCall - returns [][]interface{} - skipCallCheck bool - db *db.Database - logger *logrus.Logger - testTx *aobjs.Tx + callIndex int + db *db.Database + logger *logrus.Logger + testTx *aobjs.Tx } // assert struct `dmanTestProxy` implements `reqBusView` , `interfaces.Application`, `databaseView` interfaces @@ -42,8 +38,6 @@ var _ reqBusView = &dmanTestProxy{} var _ interfaces.Application = &dmanTestProxy{} var _ databaseView = &dmanTestProxy{} -//var _ typeProxyIface = &dmanTestProxy{} - // implementation of reqBusView interface func (p *dmanTestProxy) RequestP2PGetPendingTx(ctx context.Context, txHashes [][]byte, opts ...grpc.CallOption) ([][]byte, error) { @@ -627,52 +621,6 @@ func Test_DownloadTxs(t *testing.T) { assert.False(t, dman.downloadActor.bhc.Contains(1)) } -func generateFullChain(length int) ([]*objs.BClaims, [][][]byte, error) { - chain := []*objs.BClaims{} - txHashes := [][][]byte{} - txhash := crypto.Hasher([]byte(strconv.Itoa(1))) - txHshLst := [][]byte{txhash} - txRoot, err := objs.MakeTxRoot(txHshLst) - if err != nil { - return nil, nil, err - } - txHashes = append(txHashes, txHshLst) - bclaims := &objs.BClaims{ - ChainID: 1, - Height: 1, - TxCount: 1, - PrevBlock: crypto.Hasher([]byte("foo")), - TxRoot: txRoot, - StateRoot: crypto.Hasher([]byte("")), - HeaderRoot: crypto.Hasher([]byte("")), - } - chain = append(chain, bclaims) - for i := 1; i < length; i++ { - bhsh, err := chain[i-1].BlockHash() - if err != nil { - return nil, nil, err - } - txhash := crypto.Hasher([]byte(strconv.Itoa(i))) - txHshLst := [][]byte{txhash} - txRoot, err := objs.MakeTxRoot(txHshLst) - if err != nil { - return nil, nil, err - } - txHashes = append(txHashes, txHshLst) - bclaims := &objs.BClaims{ - ChainID: 1, - Height: uint32(len(chain) + 1), - TxCount: 1, - PrevBlock: bhsh, - TxRoot: txRoot, - StateRoot: chain[i-1].StateRoot, - HeaderRoot: chain[i-1].HeaderRoot, - } - chain = append(chain, bclaims) - } - return chain, txHashes, nil -} - func testingOwner() aobjs.Signer { signer := &crypto.Secp256k1Signer{} err := signer.SetPrivk(crypto.Hasher([]byte("secret"))) From d08f9bb1d51fa9dcad39819d8eafbb91c3038f4e Mon Sep 17 00:00:00 2001 From: Ricardo Pinto Date: Wed, 25 May 2022 15:10:17 +0000 Subject: [PATCH 10/10] - Restored unused function - Improved panic error messages --- consensus/admin/handlers.go | 22 ++++++++++++++++++++++ consensus/db/db.go | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/consensus/admin/handlers.go b/consensus/admin/handlers.go index ddf46ae5..14dc5cc4 100644 --- a/consensus/admin/handlers.go +++ b/consensus/admin/handlers.go @@ -222,6 +222,28 @@ func (ah *Handlers) AddSnapshot(bh *objs.BlockHeader, safeToProceedConsensus boo return nil } +// UpdateDynamicStorage updates dynamic storage values. +func (ah *Handlers) UpdateDynamicStorage(txn *badger.Txn, key, value string, epoch uint32) error { + mutex, ok := ah.getLock() + if !ok { + return nil + } + mutex.Lock() + defer mutex.Unlock() + + update, err := dynamics.NewUpdate(key, value, epoch) + if err != nil { + utils.DebugTrace(ah.logger, err) + return err + } + err = ah.storage.UpdateStorage(txn, update) + if err != nil { + utils.DebugTrace(ah.logger, err) + return err + } + return nil +} + // IsInitialized returns if the database has been initialized yet func (ah *Handlers) IsInitialized() bool { ah.RLock() diff --git a/consensus/db/db.go b/consensus/db/db.go index 2d0cd97a..e0bae3d7 100644 --- a/consensus/db/db.go +++ b/consensus/db/db.go @@ -1700,7 +1700,7 @@ func (pni *PendingLeafIter) Close() { func (db *Database) SetSafeToProceed(txn *badger.Txn, height uint32, isSafe bool) error { if height%constants.EpochLength != 1 { - panic(fmt.Errorf("the height must be mod 1 epoch length. height: %v\n", height)) + panic(fmt.Sprintf("the height must be mod 1 epoch length. height: %v", height)) } key := &objs.SafeToProceedKey{Prefix: dbprefix.PrefixSafeToProceed(), Height: height} k, err := key.MarshalBinary()