Skip to content

Commit

Permalink
ported mortal era encoding from it's rust implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
lyk0rian committed Jun 23, 2021
1 parent 4fec3b3 commit 9dfe2c1
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
26 changes: 26 additions & 0 deletions types/extrinsic_era.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package types

import (
"math"
"math/bits"

"github.com/centrifuge/go-substrate-rpc-client/v3/scale"
)

Expand Down Expand Up @@ -74,3 +77,26 @@ type MortalEra struct {
First byte
Second byte
}

// Mortal describes a mortal era based on a period of validity and a block number on which it should start
func Mortal(validityPeriod, currentBlock uint64) (period, phase uint64) {
calPeriod := math.Pow(2, math.Ceil(math.Log2(float64(validityPeriod))))
period = uint64(math.Min(math.Max(calPeriod, 4), 1<<16))

quantizeFactor := math.Max(float64(period>>12), 1)
quantizedPhase := float64(currentBlock%period) / quantizeFactor * quantizeFactor

phase = uint64(quantizedPhase)

return
}

// NewMortalEra encodes a mortal era based on period and phase
func NewMortalEra(period, phase uint64) MortalEra {
quantizeFactor := math.Max(float64(period>>12), 1)

trailingZeros := bits.TrailingZeros16(uint16(period))
encoded := uint16(float64(phase)/quantizeFactor)<<4 | uint16(math.Min(15, math.Max(1, float64(trailingZeros-1))))

return MortalEra{First: byte(encoded & 0xff), Second: byte(encoded >> 8)}
}
68 changes: 68 additions & 0 deletions types/extrinsic_era_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,71 @@ func TestExtrinsicEra_EncodeDecode(t *testing.T) {
assert.NoError(t, err)
assertRoundtrip(t, e)
}

func TestExtrinsicEra_MortalEraEncoding(t *testing.T) {
testCases := []struct {
Current uint64
ValidityPeriod uint64
Era MortalEra
}{
{
Current: 2251516,
ValidityPeriod: 64,
Era: MortalEra{First: 0xc5, Second: 0x03},
},
}

for _, testCase := range testCases {
period, phase := Mortal(testCase.ValidityPeriod, testCase.Current)

era := NewMortalEra(period, phase)
assert.Equal(t, testCase.Era.First, era.First)
assert.Equal(t, testCase.Era.Second, era.Second)
}
}

func TestMortal(t *testing.T) {
period, phase := Mortal(200, 1400)
assert.Equal(t, uint64(120), phase)
assert.Equal(t, uint64(256), period)
}

func TestNewMortalEra(t *testing.T) {
testCases := []struct {
Period uint64
Phase uint64
Era MortalEra
}{
{
Period: 128,
Phase: 125,
Era: MortalEra{First: 0xd6, Second: 0x07},
},
{
Period: 4096,
Phase: 3641,
Era: MortalEra{First: 0x9b, Second: 0xe3},
},
{
Period: 64,
Phase: 38,
Era: MortalEra{First: 0x65, Second: 0x02},
},
{
Period: 64,
Phase: 40,
Era: MortalEra{First: 0x85, Second: 0x02},
},
{
Period: 32768,
Phase: 20000,
Era: MortalEra{First: 78, Second: 156},
},
}

for _, testCase := range testCases {
era := NewMortalEra(testCase.Period, testCase.Phase)
assert.Equal(t, testCase.Era.First, era.First)
assert.Equal(t, testCase.Era.Second, era.Second)
}
}

0 comments on commit 9dfe2c1

Please sign in to comment.