github.com/NebulousLabs/Sia@v1.3.7/modules/consensus/block_validation_test.go (about) 1 package consensus 2 3 import ( 4 "testing" 5 6 "github.com/NebulousLabs/Sia/types" 7 ) 8 9 // mockMarshaler is a mock implementation of the encoding.GenericMarshaler 10 // interface that allows the client to pre-define the length of the marshaled 11 // data. 12 type mockMarshaler struct { 13 marshalLength uint64 14 } 15 16 // Marshal marshals an object into an empty byte slice of marshalLength. 17 func (m mockMarshaler) Marshal(interface{}) []byte { 18 return make([]byte, m.marshalLength) 19 } 20 21 // Unmarshal is not implemented. 22 func (m mockMarshaler) Unmarshal([]byte, interface{}) error { 23 panic("not implemented") 24 } 25 26 // mockClock is a mock implementation of the types.Clock interface that allows 27 // the client to pre-define a return value for Now(). 28 type mockClock struct { 29 now types.Timestamp 30 } 31 32 // Now returns mockClock's pre-defined Timestamp. 33 func (c mockClock) Now() types.Timestamp { 34 return c.now 35 } 36 37 var validateBlockTests = []struct { 38 now types.Timestamp 39 minTimestamp types.Timestamp 40 blockTimestamp types.Timestamp 41 blockSize uint64 42 errWant error 43 msg string 44 }{ 45 { 46 minTimestamp: types.Timestamp(5), 47 blockTimestamp: types.Timestamp(4), 48 errWant: errEarlyTimestamp, 49 msg: "ValidateBlock should reject blocks with timestamps that are too early", 50 }, 51 { 52 blockSize: types.BlockSizeLimit + 1, 53 errWant: errLargeBlock, 54 msg: "ValidateBlock should reject excessively large blocks", 55 }, 56 { 57 now: types.Timestamp(50), 58 blockTimestamp: types.Timestamp(50) + types.ExtremeFutureThreshold + 1, 59 errWant: errExtremeFutureTimestamp, 60 msg: "ValidateBlock should reject blocks timestamped in the extreme future", 61 }, 62 } 63 64 // TestUnitValidateBlock runs a series of unit tests for ValidateBlock. 65 func TestUnitValidateBlock(t *testing.T) { 66 // TODO(mtlynch): Populate all parameters to ValidateBlock so that everything 67 // is valid except for the attribute that causes validation to fail. (i.e. 68 // don't assume an ordering to the implementation of the validation function). 69 for _, tt := range validateBlockTests { 70 b := types.Block{ 71 Timestamp: tt.blockTimestamp, 72 } 73 blockValidator := stdBlockValidator{ 74 marshaler: mockMarshaler{ 75 marshalLength: tt.blockSize, 76 }, 77 clock: mockClock{ 78 now: tt.now, 79 }, 80 } 81 err := blockValidator.ValidateBlock(b, b.ID(), tt.minTimestamp, types.RootDepth, 0, nil) 82 if err != tt.errWant { 83 t.Errorf("%s: got %v, want %v", tt.msg, err, tt.errWant) 84 } 85 } 86 } 87 88 // TestCheckMinerPayouts probes the checkMinerPayouts function. 89 func TestCheckMinerPayouts(t *testing.T) { 90 // All tests are done at height = 0. 91 coinbase := types.CalculateCoinbase(0) 92 93 // Create a block with a single valid payout. 94 b := types.Block{ 95 MinerPayouts: []types.SiacoinOutput{ 96 {Value: coinbase}, 97 }, 98 } 99 if !checkMinerPayouts(b, 0) { 100 t.Error("payouts evaluated incorrectly when there is only one payout.") 101 } 102 103 // Try a block with an incorrect payout. 104 b = types.Block{ 105 MinerPayouts: []types.SiacoinOutput{ 106 {Value: coinbase.Sub(types.NewCurrency64(1))}, 107 }, 108 } 109 if checkMinerPayouts(b, 0) { 110 t.Error("payouts evaluated incorrectly when there is a too-small payout") 111 } 112 113 // Try a block with 2 payouts. 114 b = types.Block{ 115 MinerPayouts: []types.SiacoinOutput{ 116 {Value: coinbase.Sub(types.NewCurrency64(1))}, 117 {Value: types.NewCurrency64(1)}, 118 }, 119 } 120 if !checkMinerPayouts(b, 0) { 121 t.Error("payouts evaluated incorrectly when there are 2 payouts") 122 } 123 124 // Try a block with 2 payouts that are too large. 125 b = types.Block{ 126 MinerPayouts: []types.SiacoinOutput{ 127 {Value: coinbase}, 128 {Value: coinbase}, 129 }, 130 } 131 if checkMinerPayouts(b, 0) { 132 t.Error("payouts evaluated incorrectly when there are two large payouts") 133 } 134 135 // Create a block with an empty payout. 136 b = types.Block{ 137 MinerPayouts: []types.SiacoinOutput{ 138 {Value: coinbase}, 139 {}, 140 }, 141 } 142 if checkMinerPayouts(b, 0) { 143 t.Error("payouts evaluated incorrectly when there is only one payout.") 144 } 145 } 146 147 // TestCheckTarget probes the checkTarget function. 148 func TestCheckTarget(t *testing.T) { 149 var b types.Block 150 lowTarget := types.RootDepth 151 highTarget := types.Target{} 152 sameTarget := types.Target(b.ID()) 153 154 if !checkTarget(b, b.ID(), lowTarget) { 155 t.Error("CheckTarget failed for a low target") 156 } 157 if checkTarget(b, b.ID(), highTarget) { 158 t.Error("CheckTarget passed for a high target") 159 } 160 if !checkTarget(b, b.ID(), sameTarget) { 161 t.Error("CheckTarget failed for a same target") 162 } 163 }