Add tests for decoding packed storage

This commit is contained in:
Elizabeth Engelman 2019-07-18 16:18:20 -05:00
parent b0fff9a1dd
commit ebfb4965c7
3 changed files with 94 additions and 17 deletions

View File

@ -29,6 +29,8 @@ func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, err
return decodeUint256(row.StorageValue.Bytes()), nil return decodeUint256(row.StorageValue.Bytes()), nil
case Uint48: case Uint48:
return decodeUint48(row.StorageValue.Bytes()), nil return decodeUint48(row.StorageValue.Bytes()), nil
case Uint128:
return decodeUint128(row.StorageValue.Bytes()), nil
case Address: case Address:
return decodeAddress(row.StorageValue.Bytes()), nil return decodeAddress(row.StorageValue.Bytes()), nil
case Bytes32: case Bytes32:
@ -45,6 +47,11 @@ func decodeUint256(raw []byte) string {
return n.String() return n.String()
} }
func decodeUint128(raw []byte) string {
n := big.NewInt(0).SetBytes(raw)
return n.String()
}
func decodeUint48(raw []byte) string { func decodeUint48(raw []byte) string {
n := big.NewInt(0).SetBytes(raw) n := big.NewInt(0).SetBytes(raw)
return n.String() return n.String()
@ -54,14 +61,13 @@ func decodeAddress(raw []byte) string {
return common.BytesToAddress(raw).Hex() return common.BytesToAddress(raw).Hex()
} }
//this may need to return a slice of strings, a string for each item
func decodePackedSlot(raw []byte, packedTypes map[int]ValueType) []string{ func decodePackedSlot(raw []byte, packedTypes map[int]ValueType) []string{
storageSlot := raw storageSlot := raw
var results []string var results []string
//the reason we're using a map and not a slice is that golang doesn't guarantee the order of a slice //the reason we're using a map and not a slice is that golang doesn't guarantee the order of a slice
for _, valueType := range packedTypes { for _, valueType := range packedTypes {
lengthOfStorageSlot := len(storageSlot) lengthOfStorageSlot := len(storageSlot)
lengthOfItem := getLengthOfItem(valueType) lengthOfItem := getNumberOfBytes(valueType)
itemStartingIndex := lengthOfStorageSlot - lengthOfItem itemStartingIndex := lengthOfStorageSlot - lengthOfItem
value := storageSlot[itemStartingIndex:] value := storageSlot[itemStartingIndex:]
decodedValue := decodeIndividualItems(value, valueType) decodedValue := decodeIndividualItems(value, valueType)
@ -78,15 +84,20 @@ func decodeIndividualItems(itemBytes []byte, valueType ValueType) string {
switch valueType { switch valueType {
case Uint48: case Uint48:
return decodeUint48(itemBytes) return decodeUint48(itemBytes)
case Uint128:
return decodeUint128(itemBytes)
default: default:
panic(fmt.Sprintf("can't decode unknown type: %d", valueType)) panic(fmt.Sprintf("can't decode unknown type: %d", valueType))
} }
} }
func getLengthOfItem(valueType ValueType) int{ func getNumberOfBytes(valueType ValueType) int{
// 8 bits per byte
switch valueType { switch valueType {
case Uint48: case Uint48:
return 6 return 48 / 8
case Uint128:
return 128 / 8
default: default:
panic(fmt.Sprintf("ValueType %d not recognized", valueType)) panic(fmt.Sprintf("ValueType %d not recognized", valueType))
} }

View File

@ -17,11 +17,10 @@
package utils_test package utils_test
import ( import (
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"math/big"
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils" "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
) )
@ -38,6 +37,17 @@ var _ = Describe("Storage decoder", func() {
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String())) Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
}) })
It("decodes uint128", func() {
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000011123")
row := utils.StorageDiffRow{StorageValue: fakeInt}
metadata := utils.StorageValueMetadata{Type: utils.Uint128}
result, err := utils.Decode(row, metadata)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
})
It("decodes uint48", func() { It("decodes uint48", func() {
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123") fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123")
row := utils.StorageDiffRow{StorageValue: fakeInt} row := utils.StorageDiffRow{StorageValue: fakeInt}
@ -49,8 +59,20 @@ var _ = Describe("Storage decoder", func() {
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String())) Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
}) })
It("decodes address", func() {
fakeAddress := common.HexToAddress("0x12345")
row := utils.StorageDiffRow{StorageValue: fakeAddress.Hash()}
metadata := utils.StorageValueMetadata{Type: utils.Address}
result, err := utils.Decode(row, metadata)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(fakeAddress.Hex()))
})
Describe("when there are multiple items packed in the storage slot", func() { Describe("when there are multiple items packed in the storage slot", func() {
It("decodes the first uint48 item packed in", func() { It("decodes uint48 items", func() {
//this is a real storage data example
packedStorage := common.HexToHash("000000000000000000000000000000000000000000000002a300000000002a30") packedStorage := common.HexToHash("000000000000000000000000000000000000000000000002a300000000002a30")
row := utils.StorageDiffRow{StorageValue: packedStorage} row := utils.StorageDiffRow{StorageValue: packedStorage}
packedTypes := map[int]utils.ValueType{} packedTypes := map[int]utils.ValueType{}
@ -68,20 +90,63 @@ var _ = Describe("Storage decoder", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
expectedResult1 := big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String() expectedResult1 := big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String()
expectedResult2 := big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String() expectedResult2 := big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String()
Expect(decodedValues[0]).To(Equal(expectedResult1)) Expect(decodedValues).To(ConsistOf(expectedResult1, expectedResult2))
Expect(decodedValues[1]).To(Equal(expectedResult2))
}) })
}) It("decodes 5 uint48 items", func() {
//TODO: this packedStorageHex was generated by hand, it would be nice to test this against
//real storage data that has several items packed into it
packedStorageHex := "0000000A5D1AFFFFFFFFFFFE00000009F3C600000002A300000000002A30"
It("decodes address", func() { packedStorage := common.HexToHash(packedStorageHex)
fakeAddress := common.HexToAddress("0x12345") row := utils.StorageDiffRow{StorageValue: packedStorage}
row := utils.StorageDiffRow{StorageValue: fakeAddress.Hash()} packedTypes := map[int]utils.ValueType{}
metadata := utils.StorageValueMetadata{Type: utils.Address} packedTypes[0] = utils.Uint48
packedTypes[1] = utils.Uint48
packedTypes[2] = utils.Uint48
packedTypes[3] = utils.Uint48
packedTypes[4] = utils.Uint48
result, err := utils.Decode(row, metadata) metadata := utils.StorageValueMetadata{
Type: utils.PackedSlot,
PackedTypes: packedTypes,
}
Expect(err).NotTo(HaveOccurred()) result, err := utils.Decode(row, metadata)
Expect(result).To(Equal(fakeAddress.Hex())) decodedValues := result.([]string)
Expect(err).NotTo(HaveOccurred())
expectedResult1 := big.NewInt(0).SetBytes(common.HexToHash("A5D1A").Bytes()).String()
expectedResult2 := big.NewInt(0).SetBytes(common.HexToHash("FFFFFFFFFFFE").Bytes()).String()
expectedResult3 := big.NewInt(0).SetBytes(common.HexToHash("9F3C6").Bytes()).String()
expectedResult4 := big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String()
expectedResult5 := big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String()
Expect(decodedValues).To(ConsistOf(expectedResult1, expectedResult2, expectedResult3, expectedResult4, expectedResult5))
})
It("decodes 2 uint128 items", func() {
//TODO: this packedStorageHex was generated by hand, it would be nice to test this against
//real storage data that has several items packed into it
packedStorageHex := "000000038D7EA4C67FF8E502B6730000" +
"0000000000000000AB54A98CEB1F0AD2"
packedStorage := common.HexToHash(packedStorageHex)
row := utils.StorageDiffRow{StorageValue: packedStorage}
packedTypes := map[int]utils.ValueType{}
packedTypes[0] = utils.Uint128
packedTypes[1] = utils.Uint128
metadata := utils.StorageValueMetadata{
Type: utils.PackedSlot,
PackedTypes: packedTypes,
}
result, err := utils.Decode(row, metadata)
decodedValues := result.([]string)
Expect(err).NotTo(HaveOccurred())
expectedResult1 := big.NewInt(0).SetBytes(common.HexToHash("000000038D7EA4C67FF8E502B6730000").Bytes()).String()
expectedResult2 := big.NewInt(0).SetBytes(common.HexToHash("AB54A98CEB1F0AD2").Bytes()).String()
Expect(decodedValues).To(ConsistOf(expectedResult1, expectedResult2))
})
}) })
}) })

View File

@ -21,6 +21,7 @@ type ValueType int
const ( const (
Uint256 ValueType = iota Uint256 ValueType = iota
Uint48 Uint48
Uint128
Bytes32 Bytes32
Address Address
PackedSlot PackedSlot