github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowball/test_snowflake.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package snowball 5 6 import "testing" 7 8 const alphaPreference = 3 9 10 var terminationConditions = []terminationCondition{ 11 { 12 alphaConfidence: 3, 13 beta: 4, 14 }, 15 { 16 alphaConfidence: 4, 17 beta: 3, 18 }, 19 { 20 alphaConfidence: 5, 21 beta: 2, 22 }, 23 } 24 25 type snowflakeTestConstructor[T comparable] func(t *testing.T, alphaPreference int, terminationConditions []terminationCondition) snowflakeTest[T] 26 27 type snowflakeTest[T comparable] interface { 28 RecordPoll(count int, optionalMode T) 29 RecordUnsuccessfulPoll() 30 AssertEqual(expectedConfidences []int, expectedFinalized bool, expectedPreference T) 31 } 32 33 func executeErrorDrivenTerminatesInBetaPolls[T comparable](t *testing.T, newSnowflakeTest snowflakeTestConstructor[T], choice T) { 34 for i, terminationCondition := range terminationConditions { 35 sfTest := newSnowflakeTest(t, alphaPreference, terminationConditions) 36 37 for poll := 0; poll < terminationCondition.beta; poll++ { 38 sfTest.RecordPoll(terminationCondition.alphaConfidence, choice) 39 40 expectedConfidences := make([]int, len(terminationConditions)) 41 for j := 0; j < i+1; j++ { 42 expectedConfidences[j] = poll + 1 43 } 44 sfTest.AssertEqual(expectedConfidences, poll+1 >= terminationCondition.beta, choice) 45 } 46 } 47 } 48 49 func executeErrorDrivenReset[T comparable](t *testing.T, newSnowflakeTest snowflakeTestConstructor[T], choice T) { 50 for i, terminationCondition := range terminationConditions { 51 sfTest := newSnowflakeTest(t, alphaPreference, terminationConditions) 52 53 // Accumulate confidence up to 1 less than beta, reset, and confirm 54 // expected behavior from fresh state. 55 for poll := 0; poll < terminationCondition.beta-1; poll++ { 56 sfTest.RecordPoll(terminationCondition.alphaConfidence, choice) 57 } 58 sfTest.RecordUnsuccessfulPoll() 59 zeroConfidence := make([]int, len(terminationConditions)) 60 sfTest.AssertEqual(zeroConfidence, false, choice) 61 62 for poll := 0; poll < terminationCondition.beta; poll++ { 63 sfTest.RecordPoll(terminationCondition.alphaConfidence, choice) 64 65 expectedConfidences := make([]int, len(terminationConditions)) 66 for j := 0; j < i+1; j++ { 67 expectedConfidences[j] = poll + 1 68 } 69 sfTest.AssertEqual(expectedConfidences, poll+1 >= terminationCondition.beta, choice) 70 } 71 } 72 } 73 74 func executeErrorDrivenResetHighestAlphaConfidence[T comparable](t *testing.T, newSnowflakeTest snowflakeTestConstructor[T], choice T) { 75 sfTest := newSnowflakeTest(t, alphaPreference, terminationConditions) 76 77 sfTest.RecordPoll(5, choice) 78 sfTest.AssertEqual([]int{1, 1, 1}, false, choice) 79 sfTest.RecordPoll(4, choice) 80 sfTest.AssertEqual([]int{2, 2, 0}, false, choice) 81 sfTest.RecordPoll(3, choice) 82 sfTest.AssertEqual([]int{3, 0, 0}, false, choice) 83 sfTest.RecordPoll(5, choice) 84 sfTest.AssertEqual([]int{4, 0, 0}, true, choice) 85 } 86 87 type snowflakeTestSingleChoice[T comparable] struct { 88 name string 89 f func(*testing.T, snowflakeTestConstructor[T], T) 90 } 91 92 func getErrorDrivenSnowflakeSingleChoiceSuite[T comparable]() []snowflakeTestSingleChoice[T] { 93 return []snowflakeTestSingleChoice[T]{ 94 { 95 name: "TerminateInBetaPolls", 96 f: executeErrorDrivenTerminatesInBetaPolls[T], 97 }, 98 { 99 name: "Reset", 100 f: executeErrorDrivenReset[T], 101 }, 102 { 103 name: "ResetHighestAlphaConfidence", 104 f: executeErrorDrivenResetHighestAlphaConfidence[T], 105 }, 106 } 107 } 108 109 func executeErrorDrivenSwitchChoices[T comparable](t *testing.T, newSnowflakeTest snowflakeTestConstructor[T], choice0, choice1 T) { 110 sfTest := newSnowflakeTest(t, alphaPreference, terminationConditions) 111 112 sfTest.RecordPoll(3, choice0) 113 sfTest.AssertEqual([]int{1, 0, 0}, false, choice0) 114 115 sfTest.RecordPoll(2, choice1) 116 sfTest.AssertEqual([]int{0, 0, 0}, false, choice0) 117 118 sfTest.RecordPoll(3, choice0) 119 sfTest.AssertEqual([]int{1, 0, 0}, false, choice0) 120 121 sfTest.RecordPoll(0, choice0) 122 sfTest.AssertEqual([]int{0, 0, 0}, false, choice0) 123 124 sfTest.RecordPoll(3, choice1) 125 sfTest.AssertEqual([]int{1, 0, 0}, false, choice1) 126 127 sfTest.RecordPoll(5, choice1) 128 sfTest.AssertEqual([]int{2, 1, 1}, false, choice1) 129 sfTest.RecordPoll(5, choice1) 130 sfTest.AssertEqual([]int{3, 2, 2}, true, choice1) 131 } 132 133 type snowflakeTestMultiChoice[T comparable] struct { 134 name string 135 f func(*testing.T, snowflakeTestConstructor[T], T, T) 136 } 137 138 func getErrorDrivenSnowflakeMultiChoiceSuite[T comparable]() []snowflakeTestMultiChoice[T] { 139 return []snowflakeTestMultiChoice[T]{ 140 { 141 name: "SwitchChoices", 142 f: executeErrorDrivenSwitchChoices[T], 143 }, 144 } 145 }