251 lines
6.1 KiB
Go
251 lines
6.1 KiB
Go
package sidechain
|
|
|
|
import (
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/client"
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
func init() {
|
|
_, filename, _, _ := runtime.Caller(0)
|
|
// The ".." may change depending on you folder structure
|
|
dir := path.Join(path.Dir(filename), "../..")
|
|
err := os.Chdir(dir)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
_ = ConsensusDefault.InitHasher(2)
|
|
_ = ConsensusMini.InitHasher(2)
|
|
client.SetDefaultClientSettings(os.Getenv("MONEROD_RPC_URL"))
|
|
}
|
|
|
|
func testSideChain(s *SideChain, t *testing.T, reader io.Reader, sideHeight, mainHeight uint64, patchedBlocks ...[]byte) {
|
|
|
|
if err := s.LoadTestData(reader, patchedBlocks...); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tip := s.GetChainTip()
|
|
|
|
if tip == nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
if !tip.Verified.Load() {
|
|
t.Fatal()
|
|
}
|
|
|
|
if tip.Invalid.Load() {
|
|
t.Fatal()
|
|
}
|
|
|
|
if tip.Main.Coinbase.GenHeight != mainHeight {
|
|
t.Fatal()
|
|
}
|
|
|
|
if tip.Side.Height != sideHeight {
|
|
t.Fatal()
|
|
}
|
|
|
|
hits, misses := s.DerivationCache().ephemeralPublicKeyCache.Stats()
|
|
total := hits + misses
|
|
log.Printf("Ephemeral Public Key Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
|
|
|
|
hits, misses = s.DerivationCache().deterministicKeyCache.Stats()
|
|
total = hits + misses
|
|
log.Printf("Deterministic Key Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
|
|
|
|
hits, misses = s.DerivationCache().derivationCache.Stats()
|
|
total = hits + misses
|
|
log.Printf("Derivation Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
|
|
|
|
hits, misses = s.DerivationCache().pubKeyToPointCache.Stats()
|
|
total = hits + misses
|
|
log.Printf("PubKeyToPoint Key Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
|
|
}
|
|
|
|
func TestSideChainDefault(t *testing.T) {
|
|
|
|
s := NewSideChain(GetFakeTestServer(ConsensusDefault))
|
|
|
|
f, err := os.Open("testdata/sidechain_dump.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
testSideChain(s, t, f, 4957203, 2870010)
|
|
}
|
|
|
|
func TestSideChainDefaultPreFork(t *testing.T) {
|
|
|
|
s := NewSideChain(GetFakeTestServer(ConsensusDefault))
|
|
|
|
f, err := os.Open("testdata/old_sidechain_dump.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
testSideChain(s, t, f, 522805, 2483901)
|
|
}
|
|
|
|
func TestSideChainMini(t *testing.T) {
|
|
|
|
s := NewSideChain(GetFakeTestServer(ConsensusMini))
|
|
|
|
f, err := os.Open("testdata/sidechain_dump_mini.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
testSideChain(s, t, f, 4414446, 2870010)
|
|
}
|
|
|
|
func TestSideChainMiniPreFork(t *testing.T) {
|
|
|
|
s := NewSideChain(GetFakeTestServer(ConsensusMini))
|
|
|
|
f, err := os.Open("testdata/old_sidechain_dump_mini.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
//patch in missing blocks that are needed to newer reach sync range
|
|
block2420028, err := os.ReadFile("testdata/old_sidechain_dump_mini_2420028.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
block2420027, err := os.ReadFile("testdata/old_sidechain_dump_mini_2420027.dat")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
testSideChain(s, t, f, 2424349, 2696040, block2420028, block2420027)
|
|
}
|
|
|
|
func benchmarkResetState(tip, parent *PoolBlock, templateId types.Hash, fullId FullId, difficulty types.Difficulty, s *SideChain) {
|
|
//Remove states in maps
|
|
s.blocksByHeight.Delete(tip.Side.Height)
|
|
s.blocksByTemplateId.Delete(templateId)
|
|
s.seenBlocks.Delete(fullId)
|
|
|
|
// Update tip and depths
|
|
tip.Depth.Store(0)
|
|
parent.Depth.Store(0)
|
|
s.chainTip.Store(parent)
|
|
s.syncTip.Store(parent)
|
|
s.currentDifficulty.Store(&difficulty)
|
|
s.updateDepths(parent)
|
|
|
|
// Update verification state
|
|
tip.Verified.Store(false)
|
|
tip.Invalid.Store(false)
|
|
tip.iterationCache = nil
|
|
}
|
|
|
|
func benchSideChain(b *testing.B, s *SideChain, tipHash types.Hash) {
|
|
b.StopTimer()
|
|
|
|
tip := s.GetChainTip()
|
|
|
|
for tip.SideTemplateId(s.Consensus()) != tipHash {
|
|
s.blocksByHeight.Delete(tip.Side.Height)
|
|
s.blocksByTemplateId.Delete(tip.SideTemplateId(s.Consensus()))
|
|
s.seenBlocks.Delete(tip.FullId())
|
|
|
|
tip = s.GetParent(tip)
|
|
if tip == nil {
|
|
b.Error("nil tip")
|
|
return
|
|
}
|
|
}
|
|
templateId := tip.SideTemplateId(s.Consensus())
|
|
fullId := tip.FullId()
|
|
|
|
parent := s.GetParent(tip)
|
|
|
|
difficulty, _, _ := s.GetDifficulty(parent)
|
|
|
|
benchmarkResetState(tip, parent, templateId, fullId, difficulty, s)
|
|
|
|
var err error
|
|
|
|
b.StartTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
benchmarkResetState(tip, parent, templateId, fullId, difficulty, s)
|
|
_, err, _ = s.AddPoolBlockExternal(tip)
|
|
if err != nil {
|
|
b.Error(err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
var benchLoadedSideChain *SideChain
|
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
var isBenchmark bool
|
|
for _, arg := range os.Args {
|
|
if arg == "-test.bench" {
|
|
isBenchmark = true
|
|
}
|
|
}
|
|
|
|
if isBenchmark {
|
|
benchLoadedSideChain = NewSideChain(GetFakeTestServer(ConsensusDefault))
|
|
|
|
f, err := os.Open("testdata/sidechain_dump.dat")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
testSideChain(benchLoadedSideChain, nil, f, 4957203, 2870010)
|
|
|
|
tip := benchLoadedSideChain.GetChainTip()
|
|
|
|
// Pre-calculate PoW
|
|
for i := 0; i < 5; i++ {
|
|
tip.PowHashWithError(benchLoadedSideChain.Consensus().GetHasher(), benchLoadedSideChain.getSeedByHeightFunc())
|
|
tip = benchLoadedSideChain.GetParent(tip)
|
|
}
|
|
}
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func BenchmarkSideChainDefault_AddPoolBlockExternal(b *testing.B) {
|
|
b.ReportAllocs()
|
|
benchSideChain(b, benchLoadedSideChain, types.MustHashFromString("61ecfc1c7738eacd8b815d2e28f124b31962996ae3af4121621b5c5501f19c5d"))
|
|
}
|
|
|
|
func BenchmarkSideChainDefault_GetDifficulty(b *testing.B) {
|
|
b.ReportAllocs()
|
|
tip := benchLoadedSideChain.GetChainTip()
|
|
|
|
b.ResetTimer()
|
|
var verifyError, invalidError error
|
|
for i := 0; i < b.N; i++ {
|
|
_, verifyError, invalidError = benchLoadedSideChain.getDifficulty(tip)
|
|
if verifyError != nil {
|
|
b.Error(verifyError)
|
|
return
|
|
}
|
|
if invalidError != nil {
|
|
b.Error(invalidError)
|
|
return
|
|
}
|
|
}
|
|
}
|