github.com/okex/exchain@v1.8.0/libs/tendermint/state/execution_dds_test.go (about)

     1  package state
     2  
     3  import (
     4  	"encoding/hex"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/alicebob/miniredis/v2"
    10  	"github.com/okex/exchain/libs/iavl"
    11  	redis_cgi "github.com/okex/exchain/libs/tendermint/delta/redis-cgi"
    12  	"github.com/okex/exchain/libs/tendermint/libs/log"
    13  	"github.com/okex/exchain/libs/tendermint/types"
    14  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    15  	dbm "github.com/okex/exchain/libs/tm-db"
    16  	"github.com/stretchr/testify/require"
    17  	"github.com/tendermint/go-amino"
    18  )
    19  
    20  func getRedisClient(t *testing.T) *redis_cgi.RedisClient {
    21  	s := miniredis.RunT(t)
    22  	logger := log.TestingLogger()
    23  	ss := redis_cgi.NewRedisClient(s.Addr(), "", time.Minute, 0, logger)
    24  	return ss
    25  }
    26  
    27  func failRedisClient() *redis_cgi.RedisClient {
    28  	logger := log.TestingLogger()
    29  	ss := redis_cgi.NewRedisClient("127.0.0.1:6378", "", time.Minute, 0, logger)
    30  	return ss
    31  }
    32  
    33  func setupTest(t *testing.T) *DeltaContext {
    34  	dc := newDeltaContext(log.TestingLogger())
    35  	dc.deltaBroker = getRedisClient(t)
    36  	return dc
    37  }
    38  
    39  func bytesEqual(b1, b2 []byte) bool {
    40  	return hex.EncodeToString(b1) == hex.EncodeToString(b2)
    41  }
    42  func deltaEqual(d1, d2 *types.Deltas) bool {
    43  	if d1 == nil && d2 == nil {
    44  		return true
    45  	}
    46  	if d1 == nil || d2 == nil {
    47  		return false
    48  	}
    49  	return d1.Height == d2.Height &&
    50  		d1.From == d2.From &&
    51  		d1.CompressType == d2.CompressType &&
    52  		d1.CompressFlag == d2.CompressFlag &&
    53  		bytesEqual(d1.ABCIRsp(), d2.ABCIRsp()) &&
    54  		bytesEqual(d1.DeltasBytes(), d2.DeltasBytes()) &&
    55  		bytesEqual(d1.WatchBytes(), d2.WatchBytes())
    56  }
    57  
    58  func TestDeltaContext_prepareStateDelta(t *testing.T) {
    59  	dc := setupTest(t)
    60  	dc.downloadDelta = true
    61  
    62  	deltaInfos := make([]*DeltaInfo, 3)
    63  	for i := 0; i <= 2; i++ {
    64  		h := int64(i + 1)
    65  		deltaInfos[i] = &DeltaInfo{
    66  			from:          "0x01",
    67  			deltaLen:      1000,
    68  			deltaHeight:   h,
    69  			abciResponses: &ABCIResponses{},
    70  			treeDeltaMap:  iavl.TreeDeltaMap{},
    71  		}
    72  		dc.dataMap.insert(h, deltaInfos[i], h)
    73  	}
    74  
    75  	tests := []struct {
    76  		name     string
    77  		height   int64
    78  		wantInfo *DeltaInfo
    79  	}{
    80  		{"normal case", 1, deltaInfos[0]},
    81  		{"empty delta", 4, nil},
    82  		{"already remove", 1, nil},
    83  		{"higher height", 3, deltaInfos[2]},
    84  		{"lower remove", 2, deltaInfos[1]},
    85  	}
    86  	for _, tt := range tests {
    87  		t.Run(tt.name, func(t *testing.T) {
    88  			if gotInfo := dc.prepareStateDelta(tt.height); !reflect.DeepEqual(gotInfo, tt.wantInfo) {
    89  				t.Errorf("prepareStateDelta() = %v, want %v", gotInfo, tt.wantInfo)
    90  			}
    91  		})
    92  	}
    93  }
    94  
    95  func TestDeltaContext_download(t *testing.T) {
    96  	dc := setupTest(t)
    97  	deltas := &types.Deltas{Height: 10, Payload: types.DeltaPayload{ABCIRsp: []byte("ABCIRsp"), DeltasBytes: []byte("DeltasBytes"), WatchBytes: []byte("WatchBytes")}}
    98  	dc.uploadRoutine(deltas, 0)
    99  
   100  	tests := []struct {
   101  		name   string
   102  		height int64
   103  		wants  *types.Deltas
   104  	}{
   105  		{"normal case", 10, deltas},
   106  		{"higher height", 11, nil},
   107  		{"lower height", 9, nil},
   108  	}
   109  	for _, tt := range tests {
   110  		t.Run(tt.name, func(t *testing.T) {
   111  			_, err, mrh := dc.deltaBroker.GetDeltas(tt.height)
   112  			got, got1, got2 := dc.download(tt.height)
   113  			if !reflect.DeepEqual(got, err) {
   114  				t.Errorf("download() got = %v, want %v", got, err)
   115  			}
   116  			if !deltaEqual(got1, tt.wants) {
   117  				t.Errorf("download() got = %v, want %v", got, deltas)
   118  			}
   119  			if got2 != mrh {
   120  				t.Errorf("download() got2 = %v, want %v", got2, mrh)
   121  			}
   122  		})
   123  	}
   124  }
   125  
   126  func TestDeltaContext_upload(t *testing.T) {
   127  	dc := setupTest(t)
   128  	deltas := &types.Deltas{Payload: types.DeltaPayload{ABCIRsp: []byte("ABCIRsp"), DeltasBytes: []byte("DeltasBytes"), WatchBytes: []byte("WatchBytes")}}
   129  	okRedis := getRedisClient(t)
   130  	failRedis := failRedisClient()
   131  
   132  	tests := []struct {
   133  		name   string
   134  		r      *redis_cgi.RedisClient
   135  		deltas *types.Deltas
   136  		want   bool
   137  	}{
   138  		{"normal case", okRedis, deltas, true},
   139  		{"nil delta", okRedis, nil, false},
   140  		{"empty delta", okRedis, &types.Deltas{}, false},
   141  		{"fail redis", failRedis, deltas, false},
   142  	}
   143  	for _, tt := range tests {
   144  		t.Run(tt.name, func(t *testing.T) {
   145  			dc.deltaBroker = tt.r
   146  			if got := dc.upload(tt.deltas, 0, 0); got != tt.want {
   147  				t.Errorf("upload() = %v, want %v", got, tt.want)
   148  			}
   149  		})
   150  	}
   151  }
   152  
   153  // --------------------------------------------------------------------------------------
   154  
   155  func produceBlock() ([]*types.Block, dbm.DB) {
   156  	state, stateDB, _ := makeState(2, 2)
   157  	prevHash := state.LastBlockID.Hash
   158  	prevParts := types.PartSetHeader{}
   159  	prevBlockID := types.BlockID{Hash: prevHash, PartsHeader: prevParts}
   160  	var (
   161  		now        = tmtime.Now()
   162  		commitSig0 = types.NewCommitSigForBlock(
   163  			[]byte("Signature1"),
   164  			state.Validators.Validators[0].Address,
   165  			now)
   166  		commitSig1 = types.NewCommitSigForBlock(
   167  			[]byte("Signature2"),
   168  			state.Validators.Validators[1].Address,
   169  			now)
   170  		absentSig = types.NewCommitSigAbsent()
   171  	)
   172  
   173  	testCases := []struct {
   174  		desc                     string
   175  		lastCommitSigs           []types.CommitSig
   176  		expectedAbsentValidators []int
   177  	}{
   178  		{"none absent", []types.CommitSig{commitSig0, commitSig1}, []int{}},
   179  		{"one absent", []types.CommitSig{commitSig0, absentSig}, []int{1}},
   180  		{"multiple absent", []types.CommitSig{absentSig, absentSig}, []int{0, 1}},
   181  	}
   182  	blocks := make([]*types.Block, len(testCases))
   183  	for i, tc := range testCases {
   184  		lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs)
   185  		blocks[i], _ = state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
   186  	}
   187  
   188  	return blocks, stateDB
   189  }
   190  
   191  func produceAbciRsp() *ABCIResponses {
   192  	proxyApp := newTestApp()
   193  	proxyApp.Start()
   194  	defer proxyApp.Stop()
   195  
   196  	blocks, stateDB := produceBlock()
   197  	ctx := &executionTask{
   198  		logger:   log.TestingLogger(),
   199  		block:    blocks[0],
   200  		db:       stateDB,
   201  		proxyApp: proxyApp.Consensus(),
   202  	}
   203  
   204  	abciResponses, _ := execBlockOnProxyApp(ctx)
   205  	return abciResponses
   206  }
   207  
   208  func TestProduceDelta(t *testing.T) {
   209  	proxyApp := newTestApp()
   210  	err := proxyApp.Start()
   211  	require.Nil(t, err)
   212  	defer proxyApp.Stop()
   213  
   214  	blocks, stateDB := produceBlock()
   215  	for _, block := range blocks {
   216  		deltas, _, err := execCommitBlockDelta(proxyApp.Consensus(), block, log.TestingLogger(), stateDB)
   217  		require.Nil(t, err)
   218  		require.NotNil(t, deltas)
   219  	}
   220  }
   221  
   222  func BenchmarkMarshalJson(b *testing.B) {
   223  	abciResponses := produceAbciRsp()
   224  
   225  	b.ResetTimer()
   226  	for n := 0; n <= b.N; n++ {
   227  		types.Json.Marshal(abciResponses)
   228  	}
   229  }
   230  
   231  func BenchmarkMarshalAmino(b *testing.B) {
   232  	abciResponses := produceAbciRsp()
   233  	var cdc = amino.NewCodec()
   234  
   235  	b.ResetTimer()
   236  	for n := 0; n <= b.N; n++ {
   237  		cdc.MarshalBinaryBare(abciResponses)
   238  	}
   239  }
   240  
   241  func BenchmarkMarshalCustom(b *testing.B) {
   242  	abciResponses := produceAbciRsp()
   243  
   244  	b.ResetTimer()
   245  	for n := 0; n <= b.N; n++ {
   246  		abciResponses.MarshalToAmino(ModuleCodec)
   247  	}
   248  }
   249  
   250  func BenchmarkUnmarshalFromJson(b *testing.B) {
   251  	abciResponses := produceAbciRsp()
   252  	data, _ := types.Json.Marshal(abciResponses)
   253  
   254  	b.ReportAllocs()
   255  	b.ResetTimer()
   256  	for n := 0; n <= b.N; n++ {
   257  		ar := &ABCIResponses{}
   258  		types.Json.Unmarshal(data, ar)
   259  	}
   260  }
   261  func BenchmarkUnmarshalFromAmino(b *testing.B) {
   262  	abciResponses := produceAbciRsp()
   263  	var cdc = amino.NewCodec()
   264  	data, _ := cdc.MarshalBinaryBare(abciResponses)
   265  
   266  	b.ReportAllocs()
   267  	b.ResetTimer()
   268  	for n := 0; n <= b.N; n++ {
   269  		ar := &ABCIResponses{}
   270  		cdc.UnmarshalBinaryBare(data, ar)
   271  	}
   272  }
   273  func BenchmarkUnmarshalFromCustom(b *testing.B) {
   274  	abciResponses := produceAbciRsp()
   275  	data, _ := abciResponses.MarshalToAmino(cdc)
   276  
   277  	b.ReportAllocs()
   278  	b.ResetTimer()
   279  	for n := 0; n <= b.N; n++ {
   280  		ar := &ABCIResponses{}
   281  		ar.UnmarshalFromAmino(nil, data)
   282  	}
   283  }