Fantom-foundation/go-lachesis

View on GitHub
lachesis/genesis/account.go

Summary

Maintainability
A
0 mins
Test Coverage
package genesis

import (
    "bytes"
    "crypto/ecdsa"
    "encoding/json"
    "math/big"
    "sort"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/rlp"
    "github.com/ethereum/go-ethereum/trie"

    "github.com/Fantom-foundation/go-lachesis/inter/pos"
)

// Accounts specifies the initial state that is part of the genesis block.
type (
    Accounts map[common.Address]Account

    // Account is an account in the state of the genesis block.
    Account struct {
        Code       []byte                      `json:"code,omitempty"`
        Storage    map[common.Hash]common.Hash `json:"storage,omitempty"`
        Balance    *big.Int                    `json:"balance" gencodec:"required"`
        Nonce      uint64                      `json:"nonce,omitempty"`
        PrivateKey *ecdsa.PrivateKey           `toml:"-"`
    }
    storageElement struct {
        Key   common.Hash
        Value common.Hash
    }
    account struct {
        Code    []byte
        Storage []storageElement
        Balance *big.Int
        Nonce   uint64
    }
    accountAndAddr struct {
        Acc  account
        Addr common.Address
    }

    VAccounts struct {
        Accounts         Accounts
        Validators       pos.GValidators
        SfcContractAdmin common.Address
    }
)

// Cheaters is a slice type for storing cheaters list.
type accountsArray []accountAndAddr

// Len returns the length of s.
func (s accountsArray) Len() int { return len(s) }

// Less compares elements
func (s accountsArray) Less(i, j int) bool {
    return bytes.Compare(s[i].Addr.Bytes(), s[j].Addr.Bytes()) < 0
}

// Swap swaps the i'th and the j'th element in s.
func (s accountsArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

// GetRlp implements Rlpable and returns the i'th element of s in rlp.
func (s accountsArray) GetRlp(i int) []byte {
    enc, _ := rlp.EncodeToBytes(s[i])
    return enc
}

func (a Account) sorted() account {
    sortedStorage := make([]storageElement, 0, len(a.Storage))
    for key, val := range a.Storage {
        sortedStorage = append(sortedStorage, storageElement{
            Key:   key,
            Value: val,
        })
    }
    sort.Slice(sortedStorage, func(i, j int) bool {
        return bytes.Compare(sortedStorage[i].Key.Bytes(), sortedStorage[j].Key.Bytes()) < 0
    })

    return account{
        Code:    a.Code,
        Storage: sortedStorage,
        Balance: a.Balance,
        Nonce:   a.Nonce,
    }
}

// Addresses returns not sorted genesis addresses
func (ga Accounts) Addresses() []common.Address {
    res := make([]common.Address, 0, len(ga))
    for addr := range ga {
        res = append(res, addr)
    }
    return res
}

// sortedAccounts returns sorted genesis accounts
func (ga Accounts) sortedAccounts() accountsArray {
    res := make(accountsArray, 0, len(ga))
    for addr, acc := range ga {
        res = append(res, accountAndAddr{
            Acc:  acc.sorted(),
            Addr: addr,
        })
    }

    sort.Sort(res)

    return res
}

// Hash returns accounts hash
func (ga Accounts) Hash() common.Hash {
    return types.DeriveSha(ga.sortedAccounts(), new(trie.Trie))
}

func (ga *Accounts) UnmarshalJSON(data []byte) error {
    m := make(map[common.UnprefixedAddress]Account)
    if err := json.Unmarshal(data, &m); err != nil {
        return err
    }
    *ga = make(Accounts)
    for addr, a := range m {
        (*ga)[common.Address(addr)] = a
    }
    return nil
}

func (ga Accounts) Add(gb Accounts) {
    for addr, acc := range gb {
        ga[addr] = acc
    }
}