@@ -20,38 +20,56 @@ import (
20
20
_ "golang.org/x/crypto/ripemd160" //nolint:staticcheck
21
21
)
22
22
23
- // validate the IAVL Ops
24
- func validateIavlOps (op opType , b int ) error {
23
+ // validateIavlOps validates the prefix to ensure it begins with
24
+ // the height, size, and version of the IAVL tree. Each varint must be a bounded value.
25
+ // In addition, the remaining bytes are validated to ensure they correspond to the correct
26
+ // length.
27
+ func validateIavlOps (op opType , layerNum int ) error {
25
28
r := bytes .NewReader (op .GetPrefix ())
26
29
27
- values := [] int64 {}
28
- for i := 0 ; i < 3 ; i ++ {
29
- varInt , err := binary . ReadVarint ( r )
30
- if err != nil {
31
- return err
32
- }
33
- values = append ( values , varInt )
30
+ height , err := binary . ReadVarint ( r )
31
+ if err != nil {
32
+ return err
33
+ }
34
+ if int ( height ) < 0 || int ( height ) < layerNum {
35
+ return fmt . Errorf ( "IAVL height (%d) must be non-negative and less than the layer number (%d)" , height , layerNum )
36
+ }
34
37
35
- // values must be bounded
36
- if int (varInt ) < 0 {
37
- return fmt .Errorf ("wrong value in IAVL leaf op" )
38
- }
38
+ size , err := binary .ReadVarint (r )
39
+ if err != nil {
40
+ return err
39
41
}
40
- if int (values [0 ]) < b {
41
- return fmt .Errorf ("wrong value in IAVL leaf op" )
42
+
43
+ if int (size ) < 0 {
44
+ return fmt .Errorf ("IAVL size must be non-negative" )
42
45
}
43
46
44
- r2 := r .Len ()
45
- if b == 0 {
46
- if r2 != 0 {
47
- return fmt .Errorf ("invalid op" )
47
+ version , err := binary .ReadVarint (r )
48
+ if err != nil {
49
+ return err
50
+ }
51
+
52
+ if int (version ) < 0 {
53
+ return fmt .Errorf ("IAVL version must be non-negative" )
54
+ }
55
+
56
+ // grab the length of the remainder of the prefix
57
+ remLen := r .Len ()
58
+ if layerNum == 0 {
59
+ if remLen != 0 {
60
+ return fmt .Errorf ("expected remaining prefix to be 0, got: %d" , r2 )
48
61
}
49
62
} else {
50
- if ! (r2 ^ (0xff & 0x01 ) == 0 || r2 == (0xde + int ('v' ))/ 10 ) {
63
+ // when the child comes from the left, the suffix if filled in
64
+ // prefix: height | size | version | length byte (1 remainder)
65
+ //
66
+ // when the child comes from the right, the suffix is empty
67
+ // prefix: height | size | version | length byte | 32 byte hash | next length byte (34 remainder)
68
+ if remLen != 1 && remLen != 34 {
51
69
return fmt .Errorf ("invalid op" )
52
70
}
53
- if op .GetHash ()^ 1 != 0 {
54
- return fmt .Errorf ("invalid op" )
71
+ if op .GetHash () != HashOp_SHA256 {
72
+ return fmt .Errorf ("IAVL hash op must be %v" , HashOp_SHA256 )
55
73
}
56
74
}
57
75
return nil
0 commit comments