mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 22:56:43 +00:00
Merge pull request #1 from 0glabs/precompiles-refactor
feat: precompiles refactor
This commit is contained in:
commit
906ff6ec77
33 changed files with 7934 additions and 121 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -44,6 +44,9 @@ profile.cov
|
||||||
|
|
||||||
tests/spec-tests/
|
tests/spec-tests/
|
||||||
|
|
||||||
|
# Precompiles
|
||||||
|
core/vm/Precompiles/interfaces/node_modules
|
||||||
|
core/vm/Precompiles/interfaces/build
|
||||||
# binaries
|
# binaries
|
||||||
cmd/abidump/abidump
|
cmd/abidump/abidump
|
||||||
cmd/abigen/abigen
|
cmd/abigen/abigen
|
||||||
|
|
@ -55,4 +58,4 @@ cmd/ethkey/ethkey
|
||||||
cmd/evm/evm
|
cmd/evm/evm
|
||||||
cmd/geth/geth
|
cmd/geth/geth
|
||||||
cmd/rlpdump/rlpdump
|
cmd/rlpdump/rlpdump
|
||||||
cmd/workload/workload
|
cmd/workload/workload
|
||||||
|
|
|
||||||
166
common/bn254util/bn254util.go
Normal file
166
common/bn254util/bn254util.go
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
package bn254util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254/fp"
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
G1PointSize = 32 * 2
|
||||||
|
G2PointSize = 32 * 2 * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
FR_MODULUS, _ = new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||||
|
)
|
||||||
|
|
||||||
|
func VerifySig(sig *bn254.G1Affine, pubkey *bn254.G2Affine, msgBytes [32]byte) (bool, error) {
|
||||||
|
|
||||||
|
g2Gen := GetG2Generator()
|
||||||
|
|
||||||
|
msgPoint := MapToCurve(msgBytes)
|
||||||
|
|
||||||
|
var negSig bn254.G1Affine
|
||||||
|
negSig.Neg((*bn254.G1Affine)(sig))
|
||||||
|
|
||||||
|
P := [2]bn254.G1Affine{*msgPoint, negSig}
|
||||||
|
Q := [2]bn254.G2Affine{*pubkey, *g2Gen}
|
||||||
|
|
||||||
|
ok, err := bn254.PairingCheck(P[:], Q[:])
|
||||||
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return ok, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapToCurve(digest [32]byte) *bn254.G1Affine {
|
||||||
|
|
||||||
|
one := new(big.Int).SetUint64(1)
|
||||||
|
three := new(big.Int).SetUint64(3)
|
||||||
|
x := new(big.Int)
|
||||||
|
x.SetBytes(digest[:])
|
||||||
|
for {
|
||||||
|
// y = x^3 + 3
|
||||||
|
xP3 := new(big.Int).Exp(x, big.NewInt(3), fp.Modulus())
|
||||||
|
y := new(big.Int).Add(xP3, three)
|
||||||
|
y.Mod(y, fp.Modulus())
|
||||||
|
|
||||||
|
if y.ModSqrt(y, fp.Modulus()) == nil {
|
||||||
|
x.Add(x, one).Mod(x, fp.Modulus())
|
||||||
|
} else {
|
||||||
|
var fpX, fpY fp.Element
|
||||||
|
fpX.SetBigInt(x)
|
||||||
|
fpY.SetBigInt(y)
|
||||||
|
return &bn254.G1Affine{
|
||||||
|
X: fpX,
|
||||||
|
Y: fpY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckG1AndG2DiscreteLogEquality(pointG1 *bn254.G1Affine, pointG2 *bn254.G2Affine) (bool, error) {
|
||||||
|
negGenG1 := new(bn254.G1Affine).Neg(GetG1Generator())
|
||||||
|
return bn254.PairingCheck([]bn254.G1Affine{*pointG1, *negGenG1}, []bn254.G2Affine{*GetG2Generator(), *pointG2})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetG1Generator() *bn254.G1Affine {
|
||||||
|
g1Gen := new(bn254.G1Affine)
|
||||||
|
_, err := g1Gen.X.SetString("1")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err = g1Gen.Y.SetString("2")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return g1Gen
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetG2Generator() *bn254.G2Affine {
|
||||||
|
g2Gen := new(bn254.G2Affine)
|
||||||
|
g2Gen.X.SetString("10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||||
|
"11559732032986387107991004021392285783925812861821192530917403151452391805634")
|
||||||
|
g2Gen.Y.SetString("8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||||
|
"4082367875863433681332203403145435568316851327593401208105741076214120093531")
|
||||||
|
return g2Gen
|
||||||
|
}
|
||||||
|
|
||||||
|
func MulByGeneratorG1(a *fr.Element) *bn254.G1Affine {
|
||||||
|
g1Gen := GetG1Generator()
|
||||||
|
return new(bn254.G1Affine).ScalarMultiplication(g1Gen, a.BigInt(new(big.Int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func MulByGeneratorG2(a *fr.Element) *bn254.G2Affine {
|
||||||
|
g2Gen := GetG2Generator()
|
||||||
|
return new(bn254.G2Affine).ScalarMultiplication(g2Gen, a.BigInt(new(big.Int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SerializeG1(p *bn254.G1Affine) []byte {
|
||||||
|
b := make([]byte, 0)
|
||||||
|
tmp := p.X.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
tmp = p.Y.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeserializeG1(b []byte) *bn254.G1Affine {
|
||||||
|
p := new(bn254.G1Affine)
|
||||||
|
p.X.SetBytes(b[0:32])
|
||||||
|
p.Y.SetBytes(b[32:64])
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func SerializeG2(p *bn254.G2Affine) []byte {
|
||||||
|
b := make([]byte, 0)
|
||||||
|
tmp := p.X.A0.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
tmp = p.X.A1.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
tmp = p.Y.A0.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
tmp = p.Y.A1.Bytes()
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
b = append(b, tmp[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeserializeG2(b []byte) *bn254.G2Affine {
|
||||||
|
p := new(bn254.G2Affine)
|
||||||
|
p.X.A0.SetBytes(b[0:32])
|
||||||
|
p.X.A1.SetBytes(b[32:64])
|
||||||
|
p.Y.A0.SetBytes(b[64:96])
|
||||||
|
p.Y.A1.SetBytes(b[96:128])
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func Gamma(hash *bn254.G1Affine, signature *bn254.G1Affine, pkG1 *bn254.G1Affine, pkG2 *bn254.G2Affine) *big.Int {
|
||||||
|
toHash := make([]byte, 0)
|
||||||
|
toHash = append(toHash, SerializeG1(hash)...)
|
||||||
|
toHash = append(toHash, SerializeG1(signature)...)
|
||||||
|
toHash = append(toHash, SerializeG1(pkG1)...)
|
||||||
|
toHash = append(toHash, SerializeG2(pkG2)...)
|
||||||
|
|
||||||
|
msgHash := crypto.Keccak256(toHash)
|
||||||
|
gamma := new(big.Int)
|
||||||
|
gamma.SetBytes(msgHash)
|
||||||
|
gamma.Mod(gamma, FR_MODULUS)
|
||||||
|
return gamma
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ package common
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -486,3 +487,9 @@ func (b PrettyBytes) TerminalString() string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b))
|
return fmt.Sprintf("%#x...%x (%dB)", b[:3], b[len(b)-3:], len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Uint64ToBytes(i uint64) []byte {
|
||||||
|
b := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(b, i)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,9 @@ const (
|
||||||
// BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure.
|
// BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure.
|
||||||
// It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
|
// It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
|
||||||
BalanceChangeRevert BalanceChangeReason = 15
|
BalanceChangeRevert BalanceChangeReason = 15
|
||||||
|
|
||||||
|
// BalanceIncreaseWA0GIMint is emitted when mint happened in wrapped a0gi base precompile
|
||||||
|
BalanceIncreaseWA0GIMint BalanceChangeReason = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
// GasChangeReason is used to indicate the reason for a gas change, useful
|
// GasChangeReason is used to indicate the reason for a gas change, useful
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -29,13 +30,16 @@ import (
|
||||||
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
|
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
|
||||||
"github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
|
||||||
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -43,99 +47,160 @@ import (
|
||||||
// requires a deterministic gas count based on the input size of the Run method of the
|
// requires a deterministic gas count based on the input size of the Run method of the
|
||||||
// contract.
|
// contract.
|
||||||
type PrecompiledContract interface {
|
type PrecompiledContract interface {
|
||||||
RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
|
Address() common.Address
|
||||||
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
|
RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
|
||||||
|
Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrecompiledContracts contains the precompiled contracts supported at the given fork.
|
// PrecompiledContracts contains the precompiled contracts supported at the given fork.
|
||||||
type PrecompiledContracts map[common.Address]PrecompiledContract
|
type PrecompiledContracts map[common.Address]PrecompiledContract
|
||||||
|
|
||||||
|
var CustomPrecompiledContracts = PrecompiledContracts{
|
||||||
|
(&DASignersPrecompile{}).Address(): NewDASignersPrecompile(),
|
||||||
|
(&WrappedA0giBasePrecompile{}).Address(): NewWrappedA0giBasePrecompile(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomPrecompiles merge given precompiles with custom precompiles
|
||||||
|
func WithCustomPrecompiles(base PrecompiledContracts) PrecompiledContracts {
|
||||||
|
result := make(PrecompiledContracts)
|
||||||
|
maps.Copy(result, base)
|
||||||
|
for k, v := range CustomPrecompiledContracts {
|
||||||
|
if _, exists := result[k]; !exists {
|
||||||
|
result[k] = v
|
||||||
|
} else {
|
||||||
|
panic("Precompile address collision")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrecompiledContract is the basic interface for custom precompile contracts.
|
||||||
|
type StatefulPrecompiledContract interface {
|
||||||
|
PrecompiledContract
|
||||||
|
Abi() *abi.ABI
|
||||||
|
IsTx(string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeStatefulPrecompileCall(
|
||||||
|
p StatefulPrecompiledContract,
|
||||||
|
evm *EVM,
|
||||||
|
contract *Contract,
|
||||||
|
readonly bool,
|
||||||
|
) (
|
||||||
|
method *abi.Method,
|
||||||
|
args []interface{},
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
// parse input
|
||||||
|
if len(contract.Input) < 4 {
|
||||||
|
return nil, nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
method, err = p.Abi().MethodById(contract.Input[:4])
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
args, err = method.Inputs.Unpack(contract.Input[4:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
// readonly check
|
||||||
|
if readonly && p.IsTx(method.Name) {
|
||||||
|
return nil, nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
// Set code to a non-empty value to prevent it from being cleared by stateDB during commit() or finalise()
|
||||||
|
if !readonly && bytes.Equal(crypto.Keccak256Hash(evm.StateDB.GetCode(p.Address())).Bytes(), types.EmptyCodeHash.Bytes()) {
|
||||||
|
evm.StateDB.SetCode(p.Address(), []byte{1})
|
||||||
|
}
|
||||||
|
|
||||||
|
return method, args, nil
|
||||||
|
}
|
||||||
|
|
||||||
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
|
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
|
||||||
// contracts used in the Frontier and Homestead releases.
|
// contracts used in the Frontier and Homestead releases.
|
||||||
var PrecompiledContractsHomestead = PrecompiledContracts{
|
var PrecompiledContractsHomestead = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x1}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x2}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x4}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
}
|
})
|
||||||
|
|
||||||
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
|
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
|
||||||
// contracts used in the Byzantium release.
|
// contracts used in the Byzantium release.
|
||||||
var PrecompiledContractsByzantium = PrecompiledContracts{
|
var PrecompiledContractsByzantium = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x1}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x2}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x4}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
|
(&bigModExp{eip2565: false}).Address(): &bigModExp{eip2565: false},
|
||||||
common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{},
|
(&bn256AddByzantium{}).Address(): &bn256AddByzantium{},
|
||||||
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{},
|
(&bn256ScalarMulByzantium{}).Address(): &bn256ScalarMulByzantium{},
|
||||||
common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{},
|
(&bn256PairingByzantium{}).Address(): &bn256PairingByzantium{},
|
||||||
}
|
})
|
||||||
|
|
||||||
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
|
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
|
||||||
// contracts used in the Istanbul release.
|
// contracts used in the Istanbul release.
|
||||||
var PrecompiledContractsIstanbul = PrecompiledContracts{
|
var PrecompiledContractsIstanbul = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x1}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x2}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x4}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
|
(&bigModExp{eip2565: false}).Address(): &bigModExp{eip2565: false},
|
||||||
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
|
(&bn256AddIstanbul{}).Address(): &bn256AddIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
|
(&bn256ScalarMulIstanbul{}).Address(): &bn256ScalarMulIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
|
(&bn256PairingIstanbul{}).Address(): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x9}): &blake2F{},
|
(&blake2F{}).Address(): &blake2F{},
|
||||||
}
|
})
|
||||||
|
|
||||||
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
|
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
|
||||||
// contracts used in the Berlin release.
|
// contracts used in the Berlin release.
|
||||||
var PrecompiledContractsBerlin = PrecompiledContracts{
|
var PrecompiledContractsBerlin = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x1}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x2}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x4}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true},
|
(&bigModExp{eip2565: true}).Address(): &bigModExp{eip2565: true},
|
||||||
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
|
(&bn256AddIstanbul{}).Address(): &bn256AddIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
|
(&bn256ScalarMulIstanbul{}).Address(): &bn256ScalarMulIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
|
(&bn256PairingIstanbul{}).Address(): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x9}): &blake2F{},
|
(&blake2F{}).Address(): &blake2F{},
|
||||||
}
|
})
|
||||||
|
|
||||||
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
|
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
|
||||||
// contracts used in the Cancun release.
|
// contracts used in the Cancun release.
|
||||||
var PrecompiledContractsCancun = PrecompiledContracts{
|
var PrecompiledContractsCancun = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x1}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x2}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x4}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true},
|
(&bigModExp{eip2565: true}).Address(): &bigModExp{eip2565: true},
|
||||||
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
|
(&bn256AddIstanbul{}).Address(): &bn256AddIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
|
(&bn256ScalarMulIstanbul{}).Address(): &bn256ScalarMulIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
|
(&bn256PairingIstanbul{}).Address(): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x9}): &blake2F{},
|
(&blake2F{}).Address(): &blake2F{},
|
||||||
common.BytesToAddress([]byte{0xa}): &kzgPointEvaluation{},
|
(&kzgPointEvaluation{}).Address(): &kzgPointEvaluation{},
|
||||||
}
|
})
|
||||||
|
|
||||||
// PrecompiledContractsPrague contains the set of pre-compiled Ethereum
|
// PrecompiledContractsPrague contains the set of pre-compiled Ethereum
|
||||||
// contracts used in the Prague release.
|
// contracts used in the Prague release.
|
||||||
var PrecompiledContractsPrague = PrecompiledContracts{
|
var PrecompiledContractsPrague = WithCustomPrecompiles(PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x01}): &ecrecover{},
|
(&ecrecover{}).Address(): &ecrecover{},
|
||||||
common.BytesToAddress([]byte{0x02}): &sha256hash{},
|
(&sha256hash{}).Address(): &sha256hash{},
|
||||||
common.BytesToAddress([]byte{0x03}): &ripemd160hash{},
|
(&ripemd160hash{}).Address(): &ripemd160hash{},
|
||||||
common.BytesToAddress([]byte{0x04}): &dataCopy{},
|
(&dataCopy{}).Address(): &dataCopy{},
|
||||||
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true},
|
(&bigModExp{eip2565: true}).Address(): &bigModExp{eip2565: true},
|
||||||
common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{},
|
(&bn256AddIstanbul{}).Address(): &bn256AddIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{},
|
(&bn256ScalarMulIstanbul{}).Address(): &bn256ScalarMulIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{},
|
(&bn256PairingIstanbul{}).Address(): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{0x09}): &blake2F{},
|
(&blake2F{}).Address(): &blake2F{},
|
||||||
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
(&kzgPointEvaluation{}).Address(): &kzgPointEvaluation{},
|
||||||
common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{},
|
(&bls12381G1Add{}).Address(): &bls12381G1Add{},
|
||||||
common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{},
|
(&bls12381G1MultiExp{}).Address(): &bls12381G1MultiExp{},
|
||||||
common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{},
|
(&bls12381G2Add{}).Address(): &bls12381G2Add{},
|
||||||
common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{},
|
(&bls12381G2MultiExp{}).Address(): &bls12381G2MultiExp{},
|
||||||
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
|
(&bls12381Pairing{}).Address(): &bls12381Pairing{},
|
||||||
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
|
(&bls12381MapG1{}).Address(): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
|
(&bls12381MapG2{}).Address(): &bls12381MapG2{},
|
||||||
}
|
})
|
||||||
|
|
||||||
var PrecompiledContractsBLS = PrecompiledContractsPrague
|
var PrecompiledContractsBLS = PrecompiledContractsPrague
|
||||||
|
|
||||||
|
|
@ -218,30 +283,52 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
|
||||||
// - the returned bytes,
|
// - the returned bytes,
|
||||||
// - the _remaining_ gas,
|
// - the _remaining_ gas,
|
||||||
// - any error that occurred
|
// - any error that occurred
|
||||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
|
func RunPrecompiledContract(
|
||||||
|
evm *EVM,
|
||||||
|
p PrecompiledContract,
|
||||||
|
caller common.Address,
|
||||||
|
input []byte,
|
||||||
|
suppliedGas uint64,
|
||||||
|
value *uint256.Int,
|
||||||
|
readOnly bool,
|
||||||
|
logger *tracing.Hooks,
|
||||||
|
) (ret []byte, remainingGas uint64, err error) {
|
||||||
|
inputCopy := make([]byte, len(input))
|
||||||
|
copy(inputCopy, input)
|
||||||
|
|
||||||
|
var jumpDests map[common.Hash]bitvec
|
||||||
|
if evm != nil {
|
||||||
|
jumpDests = evm.jumpDests
|
||||||
|
}
|
||||||
|
contract := NewContract(caller, p.Address(), value, suppliedGas, jumpDests)
|
||||||
|
contract.Input = inputCopy
|
||||||
|
|
||||||
gasCost := p.RequiredGas(input)
|
gasCost := p.RequiredGas(input)
|
||||||
if suppliedGas < gasCost {
|
if !contract.UseGas(gasCost, logger, tracing.GasChangeCallPrecompiledContract) {
|
||||||
return nil, 0, ErrOutOfGas
|
return nil, 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
if logger != nil && logger.OnGasChange != nil {
|
|
||||||
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
|
output, err := p.Run(evm, contract, readOnly)
|
||||||
}
|
return output, contract.Gas, err
|
||||||
suppliedGas -= gasCost
|
|
||||||
output, err := p.Run(input)
|
|
||||||
return output, suppliedGas, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ecrecover implemented as a native contract.
|
// ecrecover implemented as a native contract.
|
||||||
type ecrecover struct{}
|
type ecrecover struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*ecrecover) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x1})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ecrecover) RequiredGas(input []byte) uint64 {
|
func (c *ecrecover) RequiredGas(input []byte) uint64 {
|
||||||
return params.EcrecoverGas
|
return params.EcrecoverGas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ecrecover) Run(input []byte) ([]byte, error) {
|
func (c *ecrecover) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
const ecRecoverInputLength = 128
|
const ecRecoverInputLength = 128
|
||||||
|
|
||||||
input = common.RightPadBytes(input, ecRecoverInputLength)
|
input := common.RightPadBytes(contract.Input, ecRecoverInputLength)
|
||||||
// "input" is (hash, v, r, s), each 32 bytes
|
// "input" is (hash, v, r, s), each 32 bytes
|
||||||
// but for ecrecover we want (r, s, v)
|
// but for ecrecover we want (r, s, v)
|
||||||
|
|
||||||
|
|
@ -272,6 +359,12 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
|
||||||
// SHA256 implemented as a native contract.
|
// SHA256 implemented as a native contract.
|
||||||
type sha256hash struct{}
|
type sha256hash struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*sha256hash) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x2})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
//
|
//
|
||||||
// This method does not require any overflow checking as the input size gas costs
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
|
@ -279,14 +372,20 @@ type sha256hash struct{}
|
||||||
func (c *sha256hash) RequiredGas(input []byte) uint64 {
|
func (c *sha256hash) RequiredGas(input []byte) uint64 {
|
||||||
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
|
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
|
||||||
}
|
}
|
||||||
func (c *sha256hash) Run(input []byte) ([]byte, error) {
|
func (c *sha256hash) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
h := sha256.Sum256(input)
|
h := sha256.Sum256(contract.Input)
|
||||||
return h[:], nil
|
return h[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RIPEMD160 implemented as a native contract.
|
// RIPEMD160 implemented as a native contract.
|
||||||
type ripemd160hash struct{}
|
type ripemd160hash struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*ripemd160hash) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x3})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
//
|
//
|
||||||
// This method does not require any overflow checking as the input size gas costs
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
|
@ -294,15 +393,21 @@ type ripemd160hash struct{}
|
||||||
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
|
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
|
||||||
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
|
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
|
||||||
}
|
}
|
||||||
func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
|
func (c *ripemd160hash) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
ripemd := ripemd160.New()
|
ripemd := ripemd160.New()
|
||||||
ripemd.Write(input)
|
ripemd.Write(contract.Input)
|
||||||
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
|
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// data copy implemented as a native contract.
|
// data copy implemented as a native contract.
|
||||||
type dataCopy struct{}
|
type dataCopy struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*dataCopy) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x4})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
//
|
//
|
||||||
// This method does not require any overflow checking as the input size gas costs
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
|
@ -310,8 +415,8 @@ type dataCopy struct{}
|
||||||
func (c *dataCopy) RequiredGas(input []byte) uint64 {
|
func (c *dataCopy) RequiredGas(input []byte) uint64 {
|
||||||
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
|
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
|
||||||
}
|
}
|
||||||
func (c *dataCopy) Run(in []byte) ([]byte, error) {
|
func (c *dataCopy) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return common.CopyBytes(in), nil
|
return common.CopyBytes(contract.Input), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bigModExp implements a native big integer exponential modular operation.
|
// bigModExp implements a native big integer exponential modular operation.
|
||||||
|
|
@ -319,6 +424,12 @@ type bigModExp struct {
|
||||||
eip2565 bool
|
eip2565 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bigModExp) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x5})
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
big1 = big.NewInt(1)
|
big1 = big.NewInt(1)
|
||||||
big3 = big.NewInt(3)
|
big3 = big.NewInt(3)
|
||||||
|
|
@ -441,7 +552,8 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
|
||||||
return gas.Uint64()
|
return gas.Uint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
func (c *bigModExp) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
var (
|
var (
|
||||||
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
|
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
|
||||||
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
|
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
|
||||||
|
|
@ -516,26 +628,38 @@ func runBn256Add(input []byte) ([]byte, error) {
|
||||||
// Istanbul consensus rules.
|
// Istanbul consensus rules.
|
||||||
type bn256AddIstanbul struct{}
|
type bn256AddIstanbul struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256AddIstanbul) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x6})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 {
|
func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256AddGasIstanbul
|
return params.Bn256AddGasIstanbul
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
|
func (c *bn256AddIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256Add(input)
|
return runBn256Add(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bn256AddByzantium implements a native elliptic curve point addition
|
// bn256AddByzantium implements a native elliptic curve point addition
|
||||||
// conforming to Byzantium consensus rules.
|
// conforming to Byzantium consensus rules.
|
||||||
type bn256AddByzantium struct{}
|
type bn256AddByzantium struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256AddByzantium) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x6})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 {
|
func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256AddGasByzantium
|
return params.Bn256AddGasByzantium
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) {
|
func (c *bn256AddByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256Add(input)
|
return runBn256Add(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
|
// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
|
||||||
|
|
@ -554,26 +678,38 @@ func runBn256ScalarMul(input []byte) ([]byte, error) {
|
||||||
// multiplication conforming to Istanbul consensus rules.
|
// multiplication conforming to Istanbul consensus rules.
|
||||||
type bn256ScalarMulIstanbul struct{}
|
type bn256ScalarMulIstanbul struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256ScalarMulIstanbul) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x7})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
|
func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256ScalarMulGasIstanbul
|
return params.Bn256ScalarMulGasIstanbul
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
|
func (c *bn256ScalarMulIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256ScalarMul(input)
|
return runBn256ScalarMul(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bn256ScalarMulByzantium implements a native elliptic curve scalar
|
// bn256ScalarMulByzantium implements a native elliptic curve scalar
|
||||||
// multiplication conforming to Byzantium consensus rules.
|
// multiplication conforming to Byzantium consensus rules.
|
||||||
type bn256ScalarMulByzantium struct{}
|
type bn256ScalarMulByzantium struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256ScalarMulByzantium) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x7})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 {
|
func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256ScalarMulGasByzantium
|
return params.Bn256ScalarMulGasByzantium
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) {
|
func (c *bn256ScalarMulByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256ScalarMul(input)
|
return runBn256ScalarMul(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -622,30 +758,48 @@ func runBn256Pairing(input []byte) ([]byte, error) {
|
||||||
// conforming to Istanbul consensus rules.
|
// conforming to Istanbul consensus rules.
|
||||||
type bn256PairingIstanbul struct{}
|
type bn256PairingIstanbul struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256PairingIstanbul) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x8})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
|
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
|
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
|
func (c *bn256PairingIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256Pairing(input)
|
return runBn256Pairing(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bn256PairingByzantium implements a pairing pre-compile for the bn256 curve
|
// bn256PairingByzantium implements a pairing pre-compile for the bn256 curve
|
||||||
// conforming to Byzantium consensus rules.
|
// conforming to Byzantium consensus rules.
|
||||||
type bn256PairingByzantium struct{}
|
type bn256PairingByzantium struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bn256PairingByzantium) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x8})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
|
func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium
|
return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) {
|
func (c *bn256PairingByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
return runBn256Pairing(input)
|
return runBn256Pairing(contract.Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
type blake2F struct{}
|
type blake2F struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*blake2F) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x9})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *blake2F) RequiredGas(input []byte) uint64 {
|
func (c *blake2F) RequiredGas(input []byte) uint64 {
|
||||||
// If the input is malformed, we can't calculate the gas, return 0 and let the
|
// If the input is malformed, we can't calculate the gas, return 0 and let the
|
||||||
// actual call choke and fault.
|
// actual call choke and fault.
|
||||||
|
|
@ -666,7 +820,8 @@ var (
|
||||||
errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
|
errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *blake2F) Run(input []byte) ([]byte, error) {
|
func (c *blake2F) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Make sure the input is valid (correct length and final flag)
|
// Make sure the input is valid (correct length and final flag)
|
||||||
if len(input) != blake2FInputLength {
|
if len(input) != blake2FInputLength {
|
||||||
return nil, errBlake2FInvalidInputLength
|
return nil, errBlake2FInvalidInputLength
|
||||||
|
|
@ -715,12 +870,19 @@ var (
|
||||||
// bls12381G1Add implements EIP-2537 G1Add precompile.
|
// bls12381G1Add implements EIP-2537 G1Add precompile.
|
||||||
type bls12381G1Add struct{}
|
type bls12381G1Add struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381G1Add) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x0b})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
|
func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bls12381G1AddGas
|
return params.Bls12381G1AddGas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
|
func (c *bls12381G1Add) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 G1Add precompile.
|
// Implements EIP-2537 G1Add precompile.
|
||||||
// > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
|
// > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
|
||||||
// > Output is an encoding of addition operation result - single G1 point (`128` bytes).
|
// > Output is an encoding of addition operation result - single G1 point (`128` bytes).
|
||||||
|
|
@ -751,6 +913,12 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
|
||||||
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
|
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
|
||||||
type bls12381G1MultiExp struct{}
|
type bls12381G1MultiExp struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381G1MultiExp) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x0c})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
|
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
|
||||||
// Calculate G1 point, scalar value pair length
|
// Calculate G1 point, scalar value pair length
|
||||||
|
|
@ -770,7 +938,8 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
|
||||||
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
|
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
|
func (c *bls12381G1MultiExp) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 G1MultiExp precompile.
|
// Implements EIP-2537 G1MultiExp precompile.
|
||||||
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
|
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
|
||||||
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
|
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
|
||||||
|
|
@ -811,12 +980,19 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
|
||||||
// bls12381G2Add implements EIP-2537 G2Add precompile.
|
// bls12381G2Add implements EIP-2537 G2Add precompile.
|
||||||
type bls12381G2Add struct{}
|
type bls12381G2Add struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381G2Add) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x0d})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
|
func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bls12381G2AddGas
|
return params.Bls12381G2AddGas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
|
func (c *bls12381G2Add) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 G2Add precompile.
|
// Implements EIP-2537 G2Add precompile.
|
||||||
// > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
|
// > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
|
||||||
// > Output is an encoding of addition operation result - single G2 point (`256` bytes).
|
// > Output is an encoding of addition operation result - single G2 point (`256` bytes).
|
||||||
|
|
@ -848,6 +1024,12 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
|
||||||
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
|
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
|
||||||
type bls12381G2MultiExp struct{}
|
type bls12381G2MultiExp struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381G2MultiExp) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x0e})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
|
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
|
||||||
// Calculate G2 point, scalar value pair length
|
// Calculate G2 point, scalar value pair length
|
||||||
|
|
@ -867,7 +1049,8 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
|
||||||
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
|
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
|
func (c *bls12381G2MultiExp) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 G2MultiExp precompile logic
|
// Implements EIP-2537 G2MultiExp precompile logic
|
||||||
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
|
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
|
||||||
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
|
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
|
||||||
|
|
@ -908,12 +1091,19 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
|
||||||
// bls12381Pairing implements EIP-2537 Pairing precompile.
|
// bls12381Pairing implements EIP-2537 Pairing precompile.
|
||||||
type bls12381Pairing struct{}
|
type bls12381Pairing struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381Pairing) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x0f})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
|
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
|
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
|
func (c *bls12381Pairing) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 Pairing precompile logic.
|
// Implements EIP-2537 Pairing precompile logic.
|
||||||
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
|
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
|
||||||
// > - `128` bytes of G1 point encoding
|
// > - `128` bytes of G1 point encoding
|
||||||
|
|
@ -1060,12 +1250,19 @@ func encodePointG2(p *bls12381.G2Affine) []byte {
|
||||||
// bls12381MapG1 implements EIP-2537 MapG1 precompile.
|
// bls12381MapG1 implements EIP-2537 MapG1 precompile.
|
||||||
type bls12381MapG1 struct{}
|
type bls12381MapG1 struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381MapG1) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x10})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
|
func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bls12381MapG1Gas
|
return params.Bls12381MapG1Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
|
func (c *bls12381MapG1) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 Map_To_G1 precompile.
|
// Implements EIP-2537 Map_To_G1 precompile.
|
||||||
// > Field-to-curve call expects an `64` bytes input that is interpreted as an element of the base field.
|
// > Field-to-curve call expects an `64` bytes input that is interpreted as an element of the base field.
|
||||||
// > Output of this call is `128` bytes and is G1 point following respective encoding rules.
|
// > Output of this call is `128` bytes and is G1 point following respective encoding rules.
|
||||||
|
|
@ -1089,12 +1286,19 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
|
||||||
// bls12381MapG2 implements EIP-2537 MapG2 precompile.
|
// bls12381MapG2 implements EIP-2537 MapG2 precompile.
|
||||||
type bls12381MapG2 struct{}
|
type bls12381MapG2 struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*bls12381MapG2) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x11})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
|
func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
|
||||||
return params.Bls12381MapG2Gas
|
return params.Bls12381MapG2Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
|
func (c *bls12381MapG2) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
// Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
|
// Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
|
||||||
// > Field-to-curve call expects an `128` bytes input that is interpreted as an element of the quadratic extension field.
|
// > Field-to-curve call expects an `128` bytes input that is interpreted as an element of the quadratic extension field.
|
||||||
// > Output of this call is `256` bytes and is G2 point following respective encoding rules.
|
// > Output of this call is `256` bytes and is G2 point following respective encoding rules.
|
||||||
|
|
@ -1122,6 +1326,12 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
|
||||||
// kzgPointEvaluation implements the EIP-4844 point evaluation precompile.
|
// kzgPointEvaluation implements the EIP-4844 point evaluation precompile.
|
||||||
type kzgPointEvaluation struct{}
|
type kzgPointEvaluation struct{}
|
||||||
|
|
||||||
|
// Address defines the precompiled contract address. This MUST match the address
|
||||||
|
// set in the precompiled contract map.
|
||||||
|
func (*kzgPointEvaluation) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0xa})
|
||||||
|
}
|
||||||
|
|
||||||
// RequiredGas estimates the gas required for running the point evaluation precompile.
|
// RequiredGas estimates the gas required for running the point evaluation precompile.
|
||||||
func (b *kzgPointEvaluation) RequiredGas(input []byte) uint64 {
|
func (b *kzgPointEvaluation) RequiredGas(input []byte) uint64 {
|
||||||
return params.BlobTxPointEvaluationPrecompileGas
|
return params.BlobTxPointEvaluationPrecompileGas
|
||||||
|
|
@ -1140,7 +1350,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Run executes the point evaluation precompile.
|
// Run executes the point evaluation precompile.
|
||||||
func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) {
|
func (b *kzgPointEvaluation) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
||||||
|
input := contract.Input
|
||||||
if len(input) != blobVerifyInputLength {
|
if len(input) != blobVerifyInputLength {
|
||||||
return nil, errBlobVerifyInvalidInputLength
|
return nil, errBlobVerifyInvalidInputLength
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FuzzPrecompiledContracts(f *testing.F) {
|
func FuzzPrecompiledContracts(f *testing.F) {
|
||||||
|
|
@ -36,7 +37,7 @@ func FuzzPrecompiledContracts(f *testing.F) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inWant := string(input)
|
inWant := string(input)
|
||||||
RunPrecompiledContract(p, input, gas, nil)
|
RunPrecompiledContract(nil, p, common.Address{}, input, gas, uint256.NewInt(0), false, nil)
|
||||||
if inHave := string(input); inWant != inHave {
|
if inHave := string(input); inWant != inHave {
|
||||||
t.Errorf("Precompiled %v modified input data", a)
|
t.Errorf("Precompiled %v modified input data", a)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// precompiledTest defines the input/output pairs for precompiled contract tests.
|
// precompiledTest defines the input/output pairs for precompiled contract tests.
|
||||||
|
|
@ -96,7 +97,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
||||||
in := common.Hex2Bytes(test.Input)
|
in := common.Hex2Bytes(test.Input)
|
||||||
gas := p.RequiredGas(in)
|
gas := p.RequiredGas(in)
|
||||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
||||||
if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil {
|
if res, _, err := RunPrecompiledContract(nil, p, common.Address{}, in, gas, uint256.NewInt(0), false, nil); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
} else if common.Bytes2Hex(res) != test.Expected {
|
} else if common.Bytes2Hex(res) != test.Expected {
|
||||||
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
|
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
|
||||||
|
|
@ -118,7 +119,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
|
||||||
gas := p.RequiredGas(in) - 1
|
gas := p.RequiredGas(in) - 1
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
|
||||||
_, _, err := RunPrecompiledContract(p, in, gas, nil)
|
_, _, err := RunPrecompiledContract(nil, p, common.Address{}, in, gas, uint256.NewInt(0), false, nil)
|
||||||
if err.Error() != "out of gas" {
|
if err.Error() != "out of gas" {
|
||||||
t.Errorf("Expected error [out of gas], got [%v]", err)
|
t.Errorf("Expected error [out of gas], got [%v]", err)
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +136,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
|
||||||
in := common.Hex2Bytes(test.Input)
|
in := common.Hex2Bytes(test.Input)
|
||||||
gas := p.RequiredGas(in)
|
gas := p.RequiredGas(in)
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
_, _, err := RunPrecompiledContract(p, in, gas, nil)
|
_, _, err := RunPrecompiledContract(nil, p, common.Address{}, in, gas, uint256.NewInt(0), false, nil)
|
||||||
if err.Error() != test.ExpectedError {
|
if err.Error() != test.ExpectedError {
|
||||||
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
|
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +168,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
copy(data, in)
|
copy(data, in)
|
||||||
res, _, err = RunPrecompiledContract(p, data, reqGas, nil)
|
res, _, err = RunPrecompiledContract(nil, p, common.Address{}, data, reqGas, uint256.NewInt(0), false, nil)
|
||||||
}
|
}
|
||||||
bench.StopTimer()
|
bench.StopTimer()
|
||||||
elapsed := uint64(time.Since(start))
|
elapsed := uint64(time.Since(start))
|
||||||
|
|
|
||||||
664
core/vm/dasigners.go
Normal file
664
core/vm/dasigners.go
Normal file
File diff suppressed because one or more lines are too long
366
core/vm/dasigners_test.go
Normal file
366
core/vm/dasigners_test.go
Normal file
|
|
@ -0,0 +1,366 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/bn254util"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm/precompiles/dasigners"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DASignersTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
|
||||||
|
abi abi.ABI
|
||||||
|
statedb *state.StateDB
|
||||||
|
evm *EVM
|
||||||
|
dasigners *DASignersPrecompile
|
||||||
|
signerOne common.Address
|
||||||
|
signerTwo common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) SetupTest() {
|
||||||
|
suite.dasigners = NewDASignersPrecompile()
|
||||||
|
suite.abi = suite.dasigners.abi
|
||||||
|
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
|
suite.statedb = statedb
|
||||||
|
suite.evm = NewEVM(BlockContext{
|
||||||
|
BlockNumber: big.NewInt(1),
|
||||||
|
}, statedb, params.TestChainConfig, Config{})
|
||||||
|
suite.signerOne = common.HexToAddress("0x0000000000000000000000000000000100000000")
|
||||||
|
suite.signerTwo = common.HexToAddress("0x0000000000000000000000000000000100000001")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) runTx(input []byte, signer common.Address, gas uint64, value *uint256.Int, readonly bool) ([]byte, error) {
|
||||||
|
suite.evm.Origin = signer
|
||||||
|
bz, _, err := RunPrecompiledContract(suite.evm, suite.dasigners, signer, input, gas, value, readonly, nil)
|
||||||
|
if err == nil {
|
||||||
|
suite.statedb.Finalise(true)
|
||||||
|
suite.statedb.Commit(suite.evm.Context.BlockNumber.Uint64(), true, false)
|
||||||
|
}
|
||||||
|
return bz, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) registerSigner(testSigner common.Address, sk *big.Int) *dasigners.IDASignersSignerDetail {
|
||||||
|
pkG1 := new(bn254.G1Affine).ScalarMultiplication(bn254util.GetG1Generator(), sk)
|
||||||
|
pkG2 := new(bn254.G2Affine).ScalarMultiplication(bn254util.GetG2Generator(), sk)
|
||||||
|
hash := dasigners.PubkeyRegistrationHash(testSigner, suite.evm.chainConfig.ChainID)
|
||||||
|
signature := new(bn254.G1Affine).ScalarMultiplication(hash, sk)
|
||||||
|
signer := dasigners.IDASignersSignerDetail{
|
||||||
|
Signer: testSigner,
|
||||||
|
Socket: "0.0.0.0:1234",
|
||||||
|
PkG1: dasigners.NewBN254G1Point(bn254util.SerializeG1(pkG1)),
|
||||||
|
PkG2: dasigners.NewBN254G2Point(bn254util.SerializeG2(pkG2)),
|
||||||
|
}
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"registerSigner",
|
||||||
|
signer,
|
||||||
|
dasigners.NewBN254G1Point(bn254util.SerializeG1(signature)),
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
oldLogs := suite.statedb.Logs()
|
||||||
|
_, err = suite.runTx(input, suite.dasigners.getRegistry(), 10000000, uint256.NewInt(0), false)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
logs := suite.statedb.Logs()
|
||||||
|
suite.Assert().EqualValues(len(logs), len(oldLogs)+2)
|
||||||
|
|
||||||
|
_, err = suite.abi.Unpack("SocketUpdated", logs[len(logs)-1].Data)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
_, err = suite.abi.Unpack("NewSigner", logs[len(logs)-2].Data)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
return &signer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) makeEpoch(testSigner common.Address) {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"makeEpoch",
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
_, err = suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), false)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) updateSocket(testSigner common.Address, signer *dasigners.IDASignersSignerDetail) {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"updateSocket",
|
||||||
|
"0.0.0.0:2345",
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
oldLogs := suite.statedb.Logs()
|
||||||
|
_, err = suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), false)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
logs := suite.statedb.Logs()
|
||||||
|
suite.Assert().EqualValues(len(logs), len(oldLogs)+1)
|
||||||
|
|
||||||
|
_, err = suite.abi.Unpack("SocketUpdated", logs[len(logs)-1].Data)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
signer.Socket = "0.0.0.0:2345"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) registerEpoch(testSigner common.Address, sk *big.Int, votes *big.Int) {
|
||||||
|
epoch := suite.dasigners.epochNumber(suite.evm) + 1
|
||||||
|
hash := dasigners.EpochRegistrationHash(testSigner, epoch, suite.evm.chainConfig.ChainID)
|
||||||
|
signature := new(bn254.G1Affine).ScalarMultiplication(hash, sk)
|
||||||
|
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"registerNextEpoch",
|
||||||
|
testSigner,
|
||||||
|
dasigners.NewBN254G1Point(bn254util.SerializeG1(signature)),
|
||||||
|
votes,
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
_, err = suite.runTx(input, suite.dasigners.getRegistry(), 10000000, uint256.NewInt(0), false)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryEpochNumber(testSigner common.Address, expected *big.Int) {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"epochNumber",
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["epochNumber"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
suite.Assert().EqualValues(out[0].(*big.Int).Uint64(), expected.Uint64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryQuorumCount(testSigner common.Address) {
|
||||||
|
epoch := suite.dasigners.epochNumber(suite.evm)
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"quorumCount",
|
||||||
|
big.NewInt(int64(epoch)),
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["quorumCount"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
suite.Assert().EqualValues(out[0], big.NewInt(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryGetSigner(testSigner common.Address, answer []dasigners.IDASignersSignerDetail) {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"getSigner",
|
||||||
|
[]common.Address{suite.signerOne, suite.signerTwo},
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["getSigner"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
suite.Assert().EqualValues(out[0], answer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryIsSigner(testSigner common.Address) {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"isSigner",
|
||||||
|
suite.signerOne,
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["isSigner"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
suite.Assert().EqualValues(out[0], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryRegisteredEpoch(testSigner common.Address, account common.Address, epoch *big.Int) bool {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"registeredEpoch",
|
||||||
|
account,
|
||||||
|
epoch,
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["registeredEpoch"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
return out[0].(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryGetQuorum(testSigner common.Address) []common.Address {
|
||||||
|
epoch := suite.dasigners.epochNumber(suite.evm)
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"getQuorum",
|
||||||
|
big.NewInt(int64(epoch)),
|
||||||
|
big.NewInt(0),
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["getQuorum"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
return out[0].([]common.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryGetQuorumRow(testSigner common.Address, row uint32) common.Address {
|
||||||
|
epoch := suite.dasigners.epochNumber(suite.evm)
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"getQuorumRow",
|
||||||
|
big.NewInt(int64(epoch)),
|
||||||
|
big.NewInt(0),
|
||||||
|
row,
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["getQuorumRow"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
return out[0].(common.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) queryGetAggPkG1(testSigner common.Address, bitmap []byte) struct {
|
||||||
|
AggPkG1 dasigners.BN254G1Point
|
||||||
|
Total *big.Int
|
||||||
|
Hit *big.Int
|
||||||
|
} {
|
||||||
|
epoch := suite.dasigners.epochNumber(suite.evm)
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"getAggPkG1",
|
||||||
|
big.NewInt(int64(epoch)),
|
||||||
|
big.NewInt(0),
|
||||||
|
bitmap,
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, testSigner, 10000000, uint256.NewInt(0), true)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["getAggPkG1"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
return struct {
|
||||||
|
AggPkG1 dasigners.BN254G1Point
|
||||||
|
Total *big.Int
|
||||||
|
Hit *big.Int
|
||||||
|
}{
|
||||||
|
AggPkG1: out[0].(dasigners.BN254G1Point),
|
||||||
|
Total: out[1].(*big.Int),
|
||||||
|
Hit: out[2].(*big.Int),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) Test_DASigners() {
|
||||||
|
// tx test
|
||||||
|
signer1 := suite.registerSigner(suite.signerOne, big.NewInt(1))
|
||||||
|
signer2 := suite.registerSigner(suite.signerTwo, big.NewInt(11))
|
||||||
|
suite.updateSocket(suite.signerOne, signer1)
|
||||||
|
suite.updateSocket(suite.signerTwo, signer2)
|
||||||
|
suite.registerEpoch(suite.signerOne, big.NewInt(1), big.NewInt(1))
|
||||||
|
suite.registerEpoch(suite.signerTwo, big.NewInt(11), big.NewInt(2))
|
||||||
|
// move to next epochs
|
||||||
|
daparams := suite.dasigners.params()
|
||||||
|
suite.queryEpochNumber(suite.signerOne, big.NewInt(0))
|
||||||
|
// move to epoch 1 & register
|
||||||
|
suite.makeEpoch(suite.signerOne)
|
||||||
|
suite.queryEpochNumber(suite.signerOne, big.NewInt(1))
|
||||||
|
suite.makeEpoch(suite.signerOne)
|
||||||
|
suite.queryEpochNumber(suite.signerOne, big.NewInt(1))
|
||||||
|
suite.registerEpoch(suite.signerOne, big.NewInt(1), big.NewInt(1))
|
||||||
|
suite.registerEpoch(suite.signerTwo, big.NewInt(11), big.NewInt(2))
|
||||||
|
// move to epoch 2
|
||||||
|
suite.evm.Context.BlockNumber = suite.evm.Context.BlockNumber.Add(suite.evm.Context.BlockNumber, daparams.EpochBlocks)
|
||||||
|
suite.makeEpoch(suite.signerOne)
|
||||||
|
suite.queryEpochNumber(suite.signerOne, big.NewInt(2))
|
||||||
|
// query test
|
||||||
|
suite.queryQuorumCount(suite.signerOne)
|
||||||
|
suite.queryGetSigner(suite.signerOne, []dasigners.IDASignersSignerDetail{*signer1, *signer2})
|
||||||
|
suite.queryIsSigner(suite.signerOne)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerOne, big.NewInt(0)), false)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerTwo, big.NewInt(0)), false)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerOne, big.NewInt(1)), true)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerTwo, big.NewInt(1)), true)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerOne, big.NewInt(2)), true)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerTwo, big.NewInt(2)), true)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerOne, big.NewInt(3)), false)
|
||||||
|
suite.Assert().EqualValues(suite.queryRegisteredEpoch(suite.signerOne, suite.signerTwo, big.NewInt(3)), false)
|
||||||
|
|
||||||
|
quorum := suite.queryGetQuorum(suite.signerOne)
|
||||||
|
suite.Assert().EqualValues(len(quorum), daparams.EncodedSlices.Int64())
|
||||||
|
cnt := map[common.Address]int{suite.signerOne: 0, suite.signerTwo: 0}
|
||||||
|
onePos := len(quorum)
|
||||||
|
twoPos := len(quorum)
|
||||||
|
for i, v := range quorum {
|
||||||
|
suite.Assert().EqualValues(suite.queryGetQuorumRow(suite.signerOne, uint32(i)), v)
|
||||||
|
cnt[v] += 1
|
||||||
|
if v == suite.signerOne {
|
||||||
|
onePos = min(onePos, i)
|
||||||
|
} else {
|
||||||
|
twoPos = min(twoPos, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suite.Assert().EqualValues(cnt[suite.signerOne], len(quorum)/3)
|
||||||
|
suite.Assert().EqualValues(cnt[suite.signerTwo], len(quorum)*2/3)
|
||||||
|
|
||||||
|
bitMap := make([]byte, len(quorum)/8)
|
||||||
|
bitMap[onePos/8] |= 1 << (onePos % 8)
|
||||||
|
suite.Assert().EqualValues(suite.queryGetAggPkG1(suite.signerOne, bitMap), struct {
|
||||||
|
AggPkG1 dasigners.BN254G1Point
|
||||||
|
Total *big.Int
|
||||||
|
Hit *big.Int
|
||||||
|
}{
|
||||||
|
AggPkG1: dasigners.NewBN254G1Point(bn254util.SerializeG1(new(bn254.G1Affine).ScalarMultiplication(bn254util.GetG1Generator(), big.NewInt(1)))),
|
||||||
|
Total: big.NewInt(int64(len(quorum))),
|
||||||
|
Hit: big.NewInt(int64(len(quorum) / 3)),
|
||||||
|
})
|
||||||
|
|
||||||
|
bitMap[twoPos/8] |= 1 << (twoPos % 8)
|
||||||
|
suite.Assert().EqualValues(suite.queryGetAggPkG1(suite.signerOne, bitMap), struct {
|
||||||
|
AggPkG1 dasigners.BN254G1Point
|
||||||
|
Total *big.Int
|
||||||
|
Hit *big.Int
|
||||||
|
}{
|
||||||
|
AggPkG1: dasigners.NewBN254G1Point(bn254util.SerializeG1(new(bn254.G1Affine).ScalarMultiplication(bn254util.GetG1Generator(), big.NewInt(1+11)))),
|
||||||
|
Total: big.NewInt(int64(len(quorum))),
|
||||||
|
Hit: big.NewInt(int64(len(quorum))),
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) getParams() dasigners.IDASignersParams {
|
||||||
|
input, err := suite.abi.Pack(
|
||||||
|
"params",
|
||||||
|
)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := suite.runTx(input, suite.signerOne, 10000000, uint256.NewInt(0), false)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
out, err := suite.abi.Methods["params"].Outputs.Unpack(bz)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
params := out[0].(dasigners.IDASignersParams)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *DASignersTestSuite) Test_Params() {
|
||||||
|
daParams := suite.getParams()
|
||||||
|
expected := suite.dasigners.params()
|
||||||
|
suite.Assert().EqualValues(expected.TokensPerVote, daParams.TokensPerVote)
|
||||||
|
suite.Assert().EqualValues(expected.MaxVotesPerSigner, daParams.MaxVotesPerSigner)
|
||||||
|
suite.Assert().EqualValues(expected.MaxQuorums, daParams.MaxQuorums)
|
||||||
|
suite.Assert().EqualValues(expected.EpochBlocks, daParams.EpochBlocks)
|
||||||
|
suite.Assert().EqualValues(expected.EncodedSlices, daParams.EncodedSlices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeeperSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(DASignersTestSuite))
|
||||||
|
}
|
||||||
|
|
@ -224,7 +224,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
evm.Context.Transfer(evm.StateDB, caller, addr, value)
|
evm.Context.Transfer(evm.StateDB, caller, addr, value)
|
||||||
|
|
||||||
if isPrecompile {
|
if isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
ret, gas, err = RunPrecompiledContract(evm, p, caller, input, gas, value, false, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
code := evm.resolveCode(addr)
|
code := evm.resolveCode(addr)
|
||||||
|
|
@ -288,7 +288,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
ret, gas, err = RunPrecompiledContract(evm, p, caller, input, gas, value, true, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
// The contract is a scoped environment for this execution context only.
|
// The contract is a scoped environment for this execution context only.
|
||||||
|
|
@ -331,7 +331,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
||||||
|
|
||||||
// It is allowed to call precompiles, even via delegatecall
|
// It is allowed to call precompiles, even via delegatecall
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
ret, gas, err = RunPrecompiledContract(evm, p, caller, input, gas, value, true, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// Initialise a new contract and make initialise the delegate values
|
// Initialise a new contract and make initialise the delegate values
|
||||||
//
|
//
|
||||||
|
|
@ -383,7 +383,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
||||||
evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount)
|
evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount)
|
||||||
|
|
||||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
ret, gas, err = RunPrecompiledContract(evm, p, caller, input, gas, new(uint256.Int), true, evm.Config.Tracer)
|
||||||
} else {
|
} else {
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
// The contract is a scoped environment for this execution context only.
|
// The contract is a scoped environment for this execution context only.
|
||||||
|
|
|
||||||
853
core/vm/precompiles/dasigners/contract.go
Normal file
853
core/vm/precompiles/dasigners/contract.go
Normal file
File diff suppressed because one or more lines are too long
14
core/vm/precompiles/dasigners/errors.go
Normal file
14
core/vm/precompiles/dasigners/errors.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package dasigners
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrQuorumIdOutOfBound = errors.New("quorum id out of bound")
|
||||||
|
ErrEpochOutOfBound = errors.New("epoch out of bound")
|
||||||
|
ErrRowIdOfBound = errors.New("row id out of bound")
|
||||||
|
ErrQuorumBitmapLengthMismatch = errors.New("quorum bitmap length mismatch")
|
||||||
|
ErrSignerNotFound = errors.New("signer not found")
|
||||||
|
ErrInvalidSender = errors.New("invalid sender")
|
||||||
|
ErrSignerExists = errors.New("signer exists")
|
||||||
|
ErrInvalidSignature = errors.New("invalid signature")
|
||||||
|
)
|
||||||
63
core/vm/precompiles/dasigners/signature.go
Normal file
63
core/vm/precompiles/dasigners/signature.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package dasigners
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/bn254util"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PubkeyRegistrationHash(operatorAddress common.Address, chainId *big.Int) *bn254.G1Affine {
|
||||||
|
toHash := make([]byte, 0)
|
||||||
|
toHash = append(toHash, operatorAddress.Bytes()...)
|
||||||
|
// make sure chainId is 32 bytes
|
||||||
|
toHash = append(toHash, common.LeftPadBytes(chainId.Bytes(), 32)...)
|
||||||
|
toHash = append(toHash, []byte("0G_BN254_Pubkey_Registration")...)
|
||||||
|
|
||||||
|
msgHash := crypto.Keccak256(toHash)
|
||||||
|
// convert to [32]byte
|
||||||
|
var msgHash32 [32]byte
|
||||||
|
copy(msgHash32[:], msgHash)
|
||||||
|
|
||||||
|
// hash to G1
|
||||||
|
return bn254util.MapToCurve(msgHash32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpochRegistrationHash(operatorAddress common.Address, epoch uint64, chainId *big.Int) *bn254.G1Affine {
|
||||||
|
toHash := make([]byte, 0)
|
||||||
|
toHash = append(toHash, operatorAddress.Bytes()...)
|
||||||
|
toHash = append(toHash, common.Uint64ToBytes(epoch)...)
|
||||||
|
toHash = append(toHash, common.LeftPadBytes(chainId.Bytes(), 32)...)
|
||||||
|
|
||||||
|
msgHash := crypto.Keccak256(toHash)
|
||||||
|
// convert to [32]byte
|
||||||
|
var msgHash32 [32]byte
|
||||||
|
copy(msgHash32[:], msgHash)
|
||||||
|
|
||||||
|
// hash to G1
|
||||||
|
return bn254util.MapToCurve(msgHash32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateSignature(s IDASignersSignerDetail, hash *bn254.G1Affine, signature *bn254.G1Affine) bool {
|
||||||
|
pubkeyG1 := bn254util.DeserializeG1(SerializeG1(s.PkG1))
|
||||||
|
pubkeyG2 := bn254util.DeserializeG2(SerializeG2(s.PkG2))
|
||||||
|
gamma := bn254util.Gamma(hash, signature, pubkeyG1, pubkeyG2)
|
||||||
|
|
||||||
|
// pairing
|
||||||
|
P := [2]bn254.G1Affine{
|
||||||
|
*new(bn254.G1Affine).Add(signature, new(bn254.G1Affine).ScalarMultiplication(pubkeyG1, gamma)),
|
||||||
|
*new(bn254.G1Affine).Add(hash, new(bn254.G1Affine).ScalarMultiplication(bn254util.GetG1Generator(), gamma)),
|
||||||
|
}
|
||||||
|
Q := [2]bn254.G2Affine{
|
||||||
|
*new(bn254.G2Affine).Neg(bn254util.GetG2Generator()),
|
||||||
|
*pubkeyG2,
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := bn254.PairingCheck(P[:], Q[:])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
117
core/vm/precompiles/dasigners/types.go
Normal file
117
core/vm/precompiles/dasigners/types.go
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
package dasigners
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BN254G1Point = struct {
|
||||||
|
X *big.Int "json:\"X\""
|
||||||
|
Y *big.Int "json:\"Y\""
|
||||||
|
}
|
||||||
|
|
||||||
|
type BN254G2Point = struct {
|
||||||
|
X [2]*big.Int "json:\"X\""
|
||||||
|
Y [2]*big.Int "json:\"Y\""
|
||||||
|
}
|
||||||
|
|
||||||
|
type IDASignersSignerDetail = struct {
|
||||||
|
Signer common.Address "json:\"signer\""
|
||||||
|
Socket string "json:\"socket\""
|
||||||
|
PkG1 BN254G1Point "json:\"pkG1\""
|
||||||
|
PkG2 BN254G2Point "json:\"pkG2\""
|
||||||
|
}
|
||||||
|
|
||||||
|
type IDASignersParams = struct {
|
||||||
|
TokensPerVote *big.Int "json:\"tokensPerVote\""
|
||||||
|
MaxVotesPerSigner *big.Int "json:\"maxVotesPerSigner\""
|
||||||
|
MaxQuorums *big.Int "json:\"maxQuorums\""
|
||||||
|
EpochBlocks *big.Int "json:\"epochBlocks\""
|
||||||
|
EncodedSlices *big.Int "json:\"encodedSlices\""
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBN254G1Point(b []byte) BN254G1Point {
|
||||||
|
return BN254G1Point{
|
||||||
|
X: new(big.Int).SetBytes(b[:32]),
|
||||||
|
Y: new(big.Int).SetBytes(b[32:64]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SerializeG1(p BN254G1Point) []byte {
|
||||||
|
b := make([]byte, 0)
|
||||||
|
b = append(b, common.LeftPadBytes(p.X.Bytes(), 32)...)
|
||||||
|
b = append(b, common.LeftPadBytes(p.Y.Bytes(), 32)...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBN254G2Point(b []byte) BN254G2Point {
|
||||||
|
return BN254G2Point{
|
||||||
|
X: [2]*big.Int{
|
||||||
|
new(big.Int).SetBytes(b[:32]),
|
||||||
|
new(big.Int).SetBytes(b[32:64]),
|
||||||
|
},
|
||||||
|
Y: [2]*big.Int{
|
||||||
|
new(big.Int).SetBytes(b[64:96]),
|
||||||
|
new(big.Int).SetBytes(b[96:128]),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SerializeG2(p BN254G2Point) []byte {
|
||||||
|
b := make([]byte, 0)
|
||||||
|
b = append(b, common.LeftPadBytes(p.X[0].Bytes(), 32)...)
|
||||||
|
b = append(b, common.LeftPadBytes(p.X[1].Bytes(), 32)...)
|
||||||
|
b = append(b, common.LeftPadBytes(p.Y[0].Bytes(), 32)...)
|
||||||
|
b = append(b, common.LeftPadBytes(p.Y[1].Bytes(), 32)...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
signerKey = []byte{0x00} // signer => registered signer info
|
||||||
|
quorumKey = []byte{0x01} // epoch => quorumId => quorum
|
||||||
|
registrationKey = []byte{0x02} // epoch => signer => signature(vrf)
|
||||||
|
votesKey = []byte{0x03} // epoch => signer => votes
|
||||||
|
quorumCountKey = []byte{0x04} // epoch => quorum count
|
||||||
|
epochNumberKey = []byte{0x05} // epoch number
|
||||||
|
epochBlockKey = []byte{0x06} // epoch number => block number
|
||||||
|
epochRegistrationKey = []byte{0x07} // epoch number => registration count
|
||||||
|
epochRegisteredSignerKey = []byte{0x08} // epoch number => index => signer
|
||||||
|
)
|
||||||
|
|
||||||
|
func SignerKey(account common.Address) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(signerKey, account.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func QuorumKey(epochNumber uint64, quorumId uint64) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(append(quorumKey, common.Uint64ToBytes(epochNumber)...), common.Uint64ToBytes(quorumId)...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegistrationKey(epochNumber uint64, account common.Address) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(append(registrationKey, common.Uint64ToBytes(epochNumber)...), account.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func VotesKey(epochNumber uint64, account common.Address) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(append(votesKey, common.Uint64ToBytes(epochNumber)...), account.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func QuorumCountKey(epochNumber uint64) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(quorumCountKey, common.Uint64ToBytes(epochNumber)...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpochNumberKey() common.Hash {
|
||||||
|
return crypto.Keccak256Hash(epochNumberKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpochBlockKey(epochNumber uint64) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(epochBlockKey, common.Uint64ToBytes(epochNumber)...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpochRegistrationKey(epochNumber uint64) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(epochRegistrationKey, common.Uint64ToBytes(epochNumber)...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpochRegisteredSignerKey(epochNumber uint64, index uint64) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(append(epochRegisteredSignerKey, common.Uint64ToBytes(epochNumber)...), common.Uint64ToBytes(index)...))
|
||||||
|
}
|
||||||
8
core/vm/precompiles/errors.go
Normal file
8
core/vm/precompiles/errors.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package precompiles
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrSenderNotOrigin = errors.New("sender not origin")
|
||||||
|
ErrSenderNotRegistry = errors.New("sender not registry")
|
||||||
|
)
|
||||||
18
core/vm/precompiles/interfaces/.solhint.json
Normal file
18
core/vm/precompiles/interfaces/.solhint.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "solhint:recommended",
|
||||||
|
"plugins": ["prettier"],
|
||||||
|
"rules": {
|
||||||
|
"avoid-low-level-calls": "off",
|
||||||
|
"compiler-version": "off",
|
||||||
|
"gas-custom-errors": "off",
|
||||||
|
"explicit-types": ["warn", "implicit"],
|
||||||
|
"func-visibility": ["warn", { "ignoreConstructors": true }],
|
||||||
|
"max-states-count": "off",
|
||||||
|
"no-empty-blocks": "off",
|
||||||
|
"no-global-import": "off",
|
||||||
|
"no-inline-assembly": "off",
|
||||||
|
"not-rely-on-time": "off",
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
"reason-string": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
485
core/vm/precompiles/interfaces/abis/IDASigners.json
Normal file
485
core/vm/precompiles/interfaces/abis/IDASigners.json
Normal file
|
|
@ -0,0 +1,485 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "signer",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "pkG1",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "struct BN254.G2Point",
|
||||||
|
"name": "pkG2",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "NewSigner",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "signer",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "socket",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "SocketUpdated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "epochNumber",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_epoch",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_quorumId",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "_quorumBitmap",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getAggPkG1",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "aggPkG1",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "total",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "hit",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_epoch",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_quorumId",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getQuorum",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address[]",
|
||||||
|
"name": "",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_epoch",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_quorumId",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint32",
|
||||||
|
"name": "_rowIndex",
|
||||||
|
"type": "uint32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getQuorumRow",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address[]",
|
||||||
|
"name": "_account",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getSigner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "signer",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "socket",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "pkG1",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G2Point",
|
||||||
|
"name": "pkG2",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct IDASigners.SignerDetail[]",
|
||||||
|
"name": "",
|
||||||
|
"type": "tuple[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "_account",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "isSigner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "makeEpoch",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "params",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "tokensPerVote",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "maxVotesPerSigner",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "maxQuorums",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "epochBlocks",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "encodedSlices",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct IDASigners.Params",
|
||||||
|
"name": "",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_epoch",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "quorumCount",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "signer",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "_signature",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "votes",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "registerNextEpoch",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "signer",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "socket",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "pkG1",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256[2]",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256[2]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G2Point",
|
||||||
|
"name": "pkG2",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct IDASigners.SignerDetail",
|
||||||
|
"name": "_signer",
|
||||||
|
"type": "tuple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "X",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "Y",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct BN254.G1Point",
|
||||||
|
"name": "_signature",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "registerSigner",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "_account",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "_epoch",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "registeredEpoch",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "_socket",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "updateSocket",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
||||||
110
core/vm/precompiles/interfaces/abis/IWrappedA0GIBase.json
Normal file
110
core/vm/precompiles/interfaces/abis/IWrappedA0GIBase.json
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "minter",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "burn",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "getWA0GI",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "minter",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "mint",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "minter",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "minterSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "cap",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "initialSupply",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "supply",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"internalType": "struct Supply",
|
||||||
|
"name": "",
|
||||||
|
"type": "tuple"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "minter",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "cap",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "initialSupply",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "setMinterCap",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
||||||
94
core/vm/precompiles/interfaces/contracts/IDASigners.sol
Normal file
94
core/vm/precompiles/interfaces/contracts/IDASigners.sol
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
library BN254 {
|
||||||
|
struct G1Point {
|
||||||
|
uint X;
|
||||||
|
uint Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoding of field elements is: X[1] * i + X[0]
|
||||||
|
struct G2Point {
|
||||||
|
uint[2] X;
|
||||||
|
uint[2] Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IDASigners {
|
||||||
|
/*=== struct ===*/
|
||||||
|
struct SignerDetail {
|
||||||
|
address signer;
|
||||||
|
string socket;
|
||||||
|
BN254.G1Point pkG1;
|
||||||
|
BN254.G2Point pkG2;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Params {
|
||||||
|
uint tokensPerVote; // deprecated
|
||||||
|
uint maxVotesPerSigner;
|
||||||
|
uint maxQuorums;
|
||||||
|
uint epochBlocks;
|
||||||
|
uint encodedSlices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=== event ===*/
|
||||||
|
event NewSigner(
|
||||||
|
address indexed signer,
|
||||||
|
BN254.G1Point pkG1,
|
||||||
|
BN254.G2Point pkG2
|
||||||
|
);
|
||||||
|
event SocketUpdated(address indexed signer, string socket);
|
||||||
|
|
||||||
|
/*=== function ===*/
|
||||||
|
function params() external view returns (Params memory);
|
||||||
|
|
||||||
|
function epochNumber() external view returns (uint);
|
||||||
|
|
||||||
|
function quorumCount(uint _epoch) external view returns (uint);
|
||||||
|
|
||||||
|
function isSigner(address _account) external view returns (bool);
|
||||||
|
|
||||||
|
function getSigner(
|
||||||
|
address[] memory _account
|
||||||
|
) external view returns (SignerDetail[] memory);
|
||||||
|
|
||||||
|
function getQuorum(
|
||||||
|
uint _epoch,
|
||||||
|
uint _quorumId
|
||||||
|
) external view returns (address[] memory);
|
||||||
|
|
||||||
|
function getQuorumRow(
|
||||||
|
uint _epoch,
|
||||||
|
uint _quorumId,
|
||||||
|
uint32 _rowIndex
|
||||||
|
) external view returns (address);
|
||||||
|
|
||||||
|
function registerSigner(
|
||||||
|
SignerDetail memory _signer,
|
||||||
|
BN254.G1Point memory _signature
|
||||||
|
) external;
|
||||||
|
|
||||||
|
function updateSocket(string memory _socket) external;
|
||||||
|
|
||||||
|
function registeredEpoch(
|
||||||
|
address _account,
|
||||||
|
uint _epoch
|
||||||
|
) external view returns (bool);
|
||||||
|
|
||||||
|
function registerNextEpoch(
|
||||||
|
address signer,
|
||||||
|
BN254.G1Point memory _signature,
|
||||||
|
uint votes
|
||||||
|
) external;
|
||||||
|
|
||||||
|
function makeEpoch() external;
|
||||||
|
|
||||||
|
function getAggPkG1(
|
||||||
|
uint _epoch,
|
||||||
|
uint _quorumId,
|
||||||
|
bytes memory _quorumBitmap
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (BN254.G1Point memory aggPkG1, uint total, uint hit);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
struct Supply {
|
||||||
|
uint256 cap;
|
||||||
|
uint256 initialSupply;
|
||||||
|
uint256 supply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title WrappedA0GIBase is a precompile for wrapped a0gi(wA0GI), it enables wA0GI mint/burn native 0g token directly.
|
||||||
|
*/
|
||||||
|
interface IWrappedA0GIBase {
|
||||||
|
/**
|
||||||
|
* @dev set the wA0GI address.
|
||||||
|
* It is designed to be called by governance module only so it's not implemented at EVM precompile side.
|
||||||
|
* @param addr address of wA0GI
|
||||||
|
*/
|
||||||
|
// function setWA0GI(address addr) external;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev get the wA0GI address.
|
||||||
|
*/
|
||||||
|
function getWA0GI() external view returns (address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev set the cap and initial supply for a minter.
|
||||||
|
* It is designed to be called by governance module only so it's not implemented at EVM precompile side.
|
||||||
|
* @param minter minter address
|
||||||
|
* @param cap mint cap
|
||||||
|
* @param initialSupply initial mint supply
|
||||||
|
*/
|
||||||
|
// function setMinterCap(address minter, uint256 cap, uint256 initialSupply) external;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev get the mint supply of given address
|
||||||
|
* @param minter minter address
|
||||||
|
*/
|
||||||
|
function minterSupply(address minter) external view returns (Supply memory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev mint a0gi to this precompile, add corresponding amount to minter's mint supply.
|
||||||
|
* If sender's final mint supply exceeds its mint cap, the transaction will revert.
|
||||||
|
* Can only be called by WA0GI.
|
||||||
|
* @param minter minter address
|
||||||
|
* @param amount amount to mint
|
||||||
|
*/
|
||||||
|
function mint(address minter, uint256 amount) external;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev burn given amount of a0gi on behalf of minter, reduce corresponding amount from sender's mint supply.
|
||||||
|
* Can only be called by WA0GI.
|
||||||
|
* @param minter minter address
|
||||||
|
* @param amount amount to burn
|
||||||
|
*/
|
||||||
|
function burn(address minter, uint256 amount) external;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Modify the mint and burn cap of given account.
|
||||||
|
* Can only be called by multi-sig admin.
|
||||||
|
* @param minter minter address
|
||||||
|
* @param cap new mint cap
|
||||||
|
* @param initialSupply new initial supply / burn cap
|
||||||
|
*/
|
||||||
|
function setMinterCap(
|
||||||
|
address minter,
|
||||||
|
uint256 cap,
|
||||||
|
uint256 initialSupply
|
||||||
|
) external;
|
||||||
|
}
|
||||||
33
core/vm/precompiles/interfaces/hardhat.config.ts
Normal file
33
core/vm/precompiles/interfaces/hardhat.config.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import "hardhat-abi-exporter";
|
||||||
|
import { HardhatUserConfig } from "hardhat/types";
|
||||||
|
|
||||||
|
const config: HardhatUserConfig = {
|
||||||
|
paths: {
|
||||||
|
artifacts: "build/artifacts",
|
||||||
|
cache: "build/cache",
|
||||||
|
sources: "contracts",
|
||||||
|
},
|
||||||
|
solidity: {
|
||||||
|
compilers: [
|
||||||
|
{
|
||||||
|
version: "0.8.20",
|
||||||
|
settings: {
|
||||||
|
evmVersion: "istanbul",
|
||||||
|
optimizer: {
|
||||||
|
enabled: true,
|
||||||
|
runs: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
abiExporter: {
|
||||||
|
path: "./abis",
|
||||||
|
runOnCompile: true,
|
||||||
|
clear: true,
|
||||||
|
flat: true,
|
||||||
|
format: "json",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
27
core/vm/precompiles/interfaces/package.json
Normal file
27
core/vm/precompiles/interfaces/package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "precompile-contracts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "hardhat compile",
|
||||||
|
"fmt:sol": "prettier 'contracts/**/*.sol' -w"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nomicfoundation/hardhat-ethers": "^3.0.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||||
|
"@typescript-eslint/parser": "6.21.0",
|
||||||
|
"eslint": "8.34.0",
|
||||||
|
"eslint-config-prettier": "8.6.0",
|
||||||
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
|
"eslint-plugin-prettier": "4.2.1",
|
||||||
|
"hardhat": "^2.22.2",
|
||||||
|
"hardhat-abi-exporter": "^2.10.1",
|
||||||
|
"prettier": "2.8.4",
|
||||||
|
"prettier-plugin-organize-imports": "3.2.4",
|
||||||
|
"prettier-plugin-solidity": "1.1.2",
|
||||||
|
"solhint": "^4.5.4",
|
||||||
|
"solhint-plugin-prettier": "0.0.5",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "4.9.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
3152
core/vm/precompiles/interfaces/yarn.lock
Normal file
3152
core/vm/precompiles/interfaces/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
305
core/vm/precompiles/wrapped_a0gi_base/contract.go
Normal file
305
core/vm/precompiles/wrapped_a0gi_base/contract.go
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
// Code generated - DO NOT EDIT.
|
||||||
|
// This file is a generated binding and any manual changes will be lost.
|
||||||
|
|
||||||
|
package wrappeda0gibase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var (
|
||||||
|
_ = errors.New
|
||||||
|
_ = big.NewInt
|
||||||
|
_ = strings.NewReader
|
||||||
|
_ = ethereum.NotFound
|
||||||
|
_ = bind.Bind
|
||||||
|
_ = common.Big1
|
||||||
|
_ = types.BloomLookup
|
||||||
|
_ = event.NewSubscription
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wrappeda0gibaseMetaData contains all meta data concerning the Wrappeda0gibase contract.
|
||||||
|
var Wrappeda0gibaseMetaData = &bind.MetaData{
|
||||||
|
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWA0GI\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"minterSupply\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"supply\",\"type\":\"uint256\"}],\"internalType\":\"structSupply\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"}],\"name\":\"setMinterCap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseABI is the input ABI used to generate the binding from.
|
||||||
|
// Deprecated: Use Wrappeda0gibaseMetaData.ABI instead.
|
||||||
|
var Wrappeda0gibaseABI = Wrappeda0gibaseMetaData.ABI
|
||||||
|
|
||||||
|
// Wrappeda0gibase is an auto generated Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibase struct {
|
||||||
|
Wrappeda0gibaseCaller // Read-only binding to the contract
|
||||||
|
Wrappeda0gibaseTransactor // Write-only binding to the contract
|
||||||
|
Wrappeda0gibaseFilterer // Log filterer for contract events
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibaseCaller struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibaseTransactor struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||||
|
type Wrappeda0gibaseFilterer struct {
|
||||||
|
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseSession is an auto generated Go binding around an Ethereum contract,
|
||||||
|
// with pre-set call and transact options.
|
||||||
|
type Wrappeda0gibaseSession struct {
|
||||||
|
Contract *Wrappeda0gibase // Generic contract binding to set the session for
|
||||||
|
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||||
|
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||||
|
// with pre-set call options.
|
||||||
|
type Wrappeda0gibaseCallerSession struct {
|
||||||
|
Contract *Wrappeda0gibaseCaller // Generic contract caller binding to set the session for
|
||||||
|
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||||
|
// with pre-set transact options.
|
||||||
|
type Wrappeda0gibaseTransactorSession struct {
|
||||||
|
Contract *Wrappeda0gibaseTransactor // Generic contract transactor binding to set the session for
|
||||||
|
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibaseRaw struct {
|
||||||
|
Contract *Wrappeda0gibase // Generic contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibaseCallerRaw struct {
|
||||||
|
Contract *Wrappeda0gibaseCaller // Generic read-only contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappeda0gibaseTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||||
|
type Wrappeda0gibaseTransactorRaw struct {
|
||||||
|
Contract *Wrappeda0gibaseTransactor // Generic write-only contract binding to access the raw methods on
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWrappeda0gibase creates a new instance of Wrappeda0gibase, bound to a specific deployed contract.
|
||||||
|
func NewWrappeda0gibase(address common.Address, backend bind.ContractBackend) (*Wrappeda0gibase, error) {
|
||||||
|
contract, err := bindWrappeda0gibase(address, backend, backend, backend)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Wrappeda0gibase{Wrappeda0gibaseCaller: Wrappeda0gibaseCaller{contract: contract}, Wrappeda0gibaseTransactor: Wrappeda0gibaseTransactor{contract: contract}, Wrappeda0gibaseFilterer: Wrappeda0gibaseFilterer{contract: contract}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWrappeda0gibaseCaller creates a new read-only instance of Wrappeda0gibase, bound to a specific deployed contract.
|
||||||
|
func NewWrappeda0gibaseCaller(address common.Address, caller bind.ContractCaller) (*Wrappeda0gibaseCaller, error) {
|
||||||
|
contract, err := bindWrappeda0gibase(address, caller, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Wrappeda0gibaseCaller{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWrappeda0gibaseTransactor creates a new write-only instance of Wrappeda0gibase, bound to a specific deployed contract.
|
||||||
|
func NewWrappeda0gibaseTransactor(address common.Address, transactor bind.ContractTransactor) (*Wrappeda0gibaseTransactor, error) {
|
||||||
|
contract, err := bindWrappeda0gibase(address, nil, transactor, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Wrappeda0gibaseTransactor{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWrappeda0gibaseFilterer creates a new log filterer instance of Wrappeda0gibase, bound to a specific deployed contract.
|
||||||
|
func NewWrappeda0gibaseFilterer(address common.Address, filterer bind.ContractFilterer) (*Wrappeda0gibaseFilterer, error) {
|
||||||
|
contract, err := bindWrappeda0gibase(address, nil, nil, filterer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Wrappeda0gibaseFilterer{contract: contract}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindWrappeda0gibase binds a generic wrapper to an already deployed contract.
|
||||||
|
func bindWrappeda0gibase(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(Wrappeda0gibaseABI))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call invokes the (constant) contract method with params as input values and
|
||||||
|
// sets the output to result. The result type might be a single field for simple
|
||||||
|
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||||
|
// returns.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||||
|
return _Wrappeda0gibase.Contract.Wrappeda0gibaseCaller.contract.Call(opts, result, method, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||||
|
// its default method if one is available.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Wrappeda0gibaseTransactor.contract.Transfer(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Wrappeda0gibaseTransactor.contract.Transact(opts, method, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call invokes the (constant) contract method with params as input values and
|
||||||
|
// sets the output to result. The result type might be a single field for simple
|
||||||
|
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||||
|
// returns.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||||
|
return _Wrappeda0gibase.Contract.contract.Call(opts, result, method, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||||
|
// its default method if one is available.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.contract.Transfer(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.contract.Transact(opts, method, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
|
||||||
|
//
|
||||||
|
// Solidity: function getWA0GI() view returns(address)
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseCaller) GetWA0GI(opts *bind.CallOpts) (common.Address, error) {
|
||||||
|
var out []interface{}
|
||||||
|
err := _Wrappeda0gibase.contract.Call(opts, &out, "getWA0GI")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return *new(common.Address), err
|
||||||
|
}
|
||||||
|
|
||||||
|
out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||||
|
|
||||||
|
return out0, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
|
||||||
|
//
|
||||||
|
// Solidity: function getWA0GI() view returns(address)
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseSession) GetWA0GI() (common.Address, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
|
||||||
|
//
|
||||||
|
// Solidity: function getWA0GI() view returns(address)
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseCallerSession) GetWA0GI() (common.Address, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinterSupply is a free data retrieval call binding the contract method 0x95609212.
|
||||||
|
//
|
||||||
|
// Solidity: function minterSupply(address minter) view returns((uint256,uint256,uint256))
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseCaller) MinterSupply(opts *bind.CallOpts, minter common.Address) (Supply, error) {
|
||||||
|
var out []interface{}
|
||||||
|
err := _Wrappeda0gibase.contract.Call(opts, &out, "minterSupply", minter)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return *new(Supply), err
|
||||||
|
}
|
||||||
|
|
||||||
|
out0 := *abi.ConvertType(out[0], new(Supply)).(*Supply)
|
||||||
|
|
||||||
|
return out0, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinterSupply is a free data retrieval call binding the contract method 0x95609212.
|
||||||
|
//
|
||||||
|
// Solidity: function minterSupply(address minter) view returns((uint256,uint256,uint256))
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseSession) MinterSupply(minter common.Address) (Supply, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.MinterSupply(&_Wrappeda0gibase.CallOpts, minter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinterSupply is a free data retrieval call binding the contract method 0x95609212.
|
||||||
|
//
|
||||||
|
// Solidity: function minterSupply(address minter) view returns((uint256,uint256,uint256))
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseCallerSession) MinterSupply(minter common.Address) (Supply, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.MinterSupply(&_Wrappeda0gibase.CallOpts, minter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burn is a paid mutator transaction binding the contract method 0x9dc29fac.
|
||||||
|
//
|
||||||
|
// Solidity: function burn(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) Burn(opts *bind.TransactOpts, minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.contract.Transact(opts, "burn", minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burn is a paid mutator transaction binding the contract method 0x9dc29fac.
|
||||||
|
//
|
||||||
|
// Solidity: function burn(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseSession) Burn(minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Burn(&_Wrappeda0gibase.TransactOpts, minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burn is a paid mutator transaction binding the contract method 0x9dc29fac.
|
||||||
|
//
|
||||||
|
// Solidity: function burn(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Burn(minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Burn(&_Wrappeda0gibase.TransactOpts, minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
|
||||||
|
//
|
||||||
|
// Solidity: function mint(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) Mint(opts *bind.TransactOpts, minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.contract.Transact(opts, "mint", minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
|
||||||
|
//
|
||||||
|
// Solidity: function mint(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseSession) Mint(minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
|
||||||
|
//
|
||||||
|
// Solidity: function mint(address minter, uint256 amount) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Mint(minter common.Address, amount *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
|
||||||
|
//
|
||||||
|
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) SetMinterCap(opts *bind.TransactOpts, minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.contract.Transact(opts, "setMinterCap", minter, cap, initialSupply)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
|
||||||
|
//
|
||||||
|
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseSession) SetMinterCap(minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.SetMinterCap(&_Wrappeda0gibase.TransactOpts, minter, cap, initialSupply)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
|
||||||
|
//
|
||||||
|
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
|
||||||
|
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) SetMinterCap(minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
|
||||||
|
return _Wrappeda0gibase.Contract.SetMinterCap(&_Wrappeda0gibase.TransactOpts, minter, cap, initialSupply)
|
||||||
|
}
|
||||||
10
core/vm/precompiles/wrapped_a0gi_base/errors.go
Normal file
10
core/vm/precompiles/wrapped_a0gi_base/errors.go
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package wrappeda0gibase
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrSenderNotWA0GI = errors.New("sender is not WA0GI")
|
||||||
|
ErrSenderNotAgency = errors.New("sender is not agency")
|
||||||
|
ErrInsufficientMintCap = errors.New("insufficient mint cap")
|
||||||
|
ErrInsufficientMintSupply = errors.New("insufficient mint supply")
|
||||||
|
)
|
||||||
22
core/vm/precompiles/wrapped_a0gi_base/types.go
Normal file
22
core/vm/precompiles/wrapped_a0gi_base/types.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package wrappeda0gibase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Supply = struct {
|
||||||
|
Cap *big.Int "json:\"cap\""
|
||||||
|
InitialSupply *big.Int "json:\"initialSupply\""
|
||||||
|
Supply *big.Int "json:\"supply\""
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
supplyKey = []byte{0x00}
|
||||||
|
)
|
||||||
|
|
||||||
|
func SupplyKey(account common.Address) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(append(supplyKey, account.Bytes()...))
|
||||||
|
}
|
||||||
46
core/vm/statedb_utils.go
Normal file
46
core/vm/statedb_utils.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StoreBytes stores an arbitrary-length []byte into StateDB using multiple storage slots.
|
||||||
|
func StoreBytes(statedb StateDB, addr common.Address, key common.Hash, value []byte) {
|
||||||
|
// Compute the storage root key (keccak256(key)) as the base
|
||||||
|
lengthKey := crypto.Keccak256Hash(key.Bytes())
|
||||||
|
statedb.SetState(addr, lengthKey, common.BigToHash(big.NewInt(int64(len(value)))))
|
||||||
|
|
||||||
|
// Split value into 32-byte chunks and store them
|
||||||
|
for i := 0; i < len(value); i += 32 {
|
||||||
|
end := i + 32
|
||||||
|
if end > len(value) {
|
||||||
|
end = len(value)
|
||||||
|
}
|
||||||
|
chunk := make([]byte, 32)
|
||||||
|
copy(chunk, value[i:end]) // Copy to ensure 32 bytes, padding with zeros
|
||||||
|
|
||||||
|
// Compute storage key: keccak256(lengthKey || index)
|
||||||
|
storageKey := crypto.Keccak256Hash(append(lengthKey.Bytes(), common.Uint64ToBytes(uint64(i/32))...))
|
||||||
|
statedb.SetState(addr, storageKey, common.BytesToHash(chunk))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBytes retrieves an arbitrary-length []byte from StateDB.
|
||||||
|
func LoadBytes(statedb StateDB, addr common.Address, key common.Hash) []byte {
|
||||||
|
// Read length
|
||||||
|
lengthKey := crypto.Keccak256Hash(key.Bytes())
|
||||||
|
length := statedb.GetState(addr, lengthKey).Big().Uint64()
|
||||||
|
|
||||||
|
// Read stored chunks
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
for i := uint64(0); i < length; i += 32 {
|
||||||
|
storageKey := crypto.Keccak256Hash(append(lengthKey.Bytes(), common.Uint64ToBytes(uint64(i/32))...))
|
||||||
|
chunk := statedb.GetState(addr, storageKey).Bytes()
|
||||||
|
buffer.Write(chunk)
|
||||||
|
}
|
||||||
|
return buffer.Bytes()[:length] // Trim padding
|
||||||
|
}
|
||||||
295
core/vm/wrapped_a0gi_base.go
Normal file
295
core/vm/wrapped_a0gi_base.go
Normal file
File diff suppressed because one or more lines are too long
657
core/vm/wrapped_a0gi_base_test.go
Normal file
657
core/vm/wrapped_a0gi_base_test.go
Normal file
|
|
@ -0,0 +1,657 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
wrappeda0gibase "github.com/ethereum/go-ethereum/core/vm/precompiles/wrapped_a0gi_base"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WrappedA0giBaseTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
|
||||||
|
abi abi.ABI
|
||||||
|
statedb *state.StateDB
|
||||||
|
evm *EVM
|
||||||
|
wa0gibase *WrappedA0giBasePrecompile
|
||||||
|
signerOne common.Address
|
||||||
|
signerTwo common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *WrappedA0giBaseTestSuite) SetupTest() {
|
||||||
|
suite.wa0gibase = NewWrappedA0giBasePrecompile()
|
||||||
|
suite.abi = suite.wa0gibase.abi
|
||||||
|
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
|
suite.statedb = statedb
|
||||||
|
suite.evm = NewEVM(BlockContext{
|
||||||
|
BlockNumber: big.NewInt(1),
|
||||||
|
}, statedb, params.TestChainConfig, Config{})
|
||||||
|
suite.signerOne = common.HexToAddress("0x0000000000000000000000000000000100000000")
|
||||||
|
suite.signerTwo = common.HexToAddress("0x0000000000000000000000000000000100000001")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *WrappedA0giBaseTestSuite) runTx(input []byte, signer common.Address, gas uint64, value *uint256.Int, readonly bool) ([]byte, error) {
|
||||||
|
suite.evm.Origin = signer
|
||||||
|
bz, _, err := RunPrecompiledContract(suite.evm, suite.wa0gibase, signer, input, gas, value, readonly, nil)
|
||||||
|
if err == nil {
|
||||||
|
suite.statedb.Finalise(true)
|
||||||
|
suite.statedb.Commit(suite.evm.Context.BlockNumber.Uint64(), true, false)
|
||||||
|
}
|
||||||
|
return bz, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestGetW0GI() {
|
||||||
|
method := WrappedA0GIBaseFunctionGetWA0GI
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
malleate func() []byte
|
||||||
|
postCheck func(bz []byte)
|
||||||
|
gas uint64
|
||||||
|
expErr bool
|
||||||
|
errContains string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func(data []byte) {
|
||||||
|
out, err := s.abi.Methods[method].Outputs.Unpack(data)
|
||||||
|
s.Require().NoError(err, "failed to unpack output")
|
||||||
|
wa0gi := out[0].(common.Address)
|
||||||
|
s.Require().Equal(wa0gi, s.wa0gibase.getWA0GI())
|
||||||
|
// fmt.Println(wa0gi)
|
||||||
|
},
|
||||||
|
100000,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(tc.name, func() {
|
||||||
|
s.SetupTest()
|
||||||
|
|
||||||
|
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000, uint256.NewInt(0), true)
|
||||||
|
|
||||||
|
if tc.expErr {
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Contains(err.Error(), tc.errContains)
|
||||||
|
} else {
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(bz)
|
||||||
|
tc.postCheck(bz)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestMinterSupply() {
|
||||||
|
method := WrappedA0GIBaseFunctionMinterSupply
|
||||||
|
agency := s.wa0gibase.getAgency()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
malleate func() []byte
|
||||||
|
postCheck func(bz []byte)
|
||||||
|
gas uint64
|
||||||
|
expErr bool
|
||||||
|
errContains string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"non-empty",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerOne,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func(data []byte) {
|
||||||
|
out, err := s.abi.Methods[method].Outputs.Unpack(data)
|
||||||
|
s.Require().NoError(err, "failed to unpack output")
|
||||||
|
supply := out[0].(wrappeda0gibase.Supply)
|
||||||
|
fmt.Println(supply)
|
||||||
|
s.Require().Equal(supply.Cap, big.NewInt(8e18))
|
||||||
|
s.Require().Equal(supply.InitialSupply, big.NewInt(4e18))
|
||||||
|
s.Require().Equal(supply.Supply, big.NewInt(4e18+1e18))
|
||||||
|
// fmt.Println(wa0gi)
|
||||||
|
},
|
||||||
|
100000,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
}, {
|
||||||
|
"empty",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerTwo,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func(data []byte) {
|
||||||
|
out, err := s.abi.Methods[method].Outputs.Unpack(data)
|
||||||
|
s.Require().NoError(err, "failed to unpack output")
|
||||||
|
supply := out[0].(wrappeda0gibase.Supply)
|
||||||
|
s.Require().Equal(supply.Cap.Bytes(), big.NewInt(0).Bytes())
|
||||||
|
s.Require().Equal(supply.InitialSupply.Bytes(), big.NewInt(0).Bytes())
|
||||||
|
s.Require().Equal(supply.Supply.Bytes(), big.NewInt(0).Bytes())
|
||||||
|
// fmt.Println(wa0gi)
|
||||||
|
},
|
||||||
|
100000,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(tc.name, func() {
|
||||||
|
s.SetupTest()
|
||||||
|
// set minter cap
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(8e18),
|
||||||
|
big.NewInt(4e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
// mint
|
||||||
|
input, err = s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionMint,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(1e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, s.wa0gibase.getWA0GI(), 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
|
||||||
|
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000, uint256.NewInt(0), true)
|
||||||
|
|
||||||
|
if tc.expErr {
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Contains(err.Error(), tc.errContains)
|
||||||
|
} else {
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(bz)
|
||||||
|
tc.postCheck(bz)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestMint() {
|
||||||
|
method := WrappedA0GIBaseFunctionMint
|
||||||
|
agency := s.wa0gibase.getAgency()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
malleate func() []byte
|
||||||
|
postCheck func()
|
||||||
|
gas uint64
|
||||||
|
expErr bool
|
||||||
|
errContains string
|
||||||
|
isSenderWA0GI bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(1e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
supply, err := s.wa0gibase.getMinterSupply(s.evm, s.signerOne)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
s.Require().Equal(supply.Cap, big.NewInt(8e18))
|
||||||
|
s.Require().Equal(supply.InitialSupply, big.NewInt(4e18))
|
||||||
|
s.Require().Equal(supply.Supply, big.NewInt(4e18+1e18))
|
||||||
|
},
|
||||||
|
100000,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
}, {
|
||||||
|
"fail",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(9e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {},
|
||||||
|
100000,
|
||||||
|
true,
|
||||||
|
"insufficient mint cap",
|
||||||
|
true,
|
||||||
|
}, {
|
||||||
|
"invalid sender",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerTwo,
|
||||||
|
big.NewInt(9e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {},
|
||||||
|
100000,
|
||||||
|
true,
|
||||||
|
"sender is not WA0GI",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(tc.name, func() {
|
||||||
|
s.SetupTest()
|
||||||
|
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(8e18),
|
||||||
|
big.NewInt(4e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
|
||||||
|
if tc.isSenderWA0GI {
|
||||||
|
_, err = s.runTx(tc.malleate(), s.wa0gibase.getWA0GI(), 10000000, uint256.NewInt(0), false)
|
||||||
|
} else {
|
||||||
|
_, err = s.runTx(tc.malleate(), s.signerTwo, 10000000, uint256.NewInt(0), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expErr {
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Contains(err.Error(), tc.errContains)
|
||||||
|
} else {
|
||||||
|
s.Require().NoError(err)
|
||||||
|
tc.postCheck()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestBurn() {
|
||||||
|
method := WrappedA0GIBaseFunctionBurn
|
||||||
|
agency := s.wa0gibase.getAgency()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
malleate func() []byte
|
||||||
|
postCheck func()
|
||||||
|
gas uint64
|
||||||
|
expErr bool
|
||||||
|
errContains string
|
||||||
|
isSenderWA0GI bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(1e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
supply, err := s.wa0gibase.getMinterSupply(s.evm, s.signerOne)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
s.Require().Equal(supply.Cap, big.NewInt(8e18))
|
||||||
|
s.Require().Equal(supply.InitialSupply, big.NewInt(4e18))
|
||||||
|
s.Require().Equal(supply.Supply, big.NewInt(3e18))
|
||||||
|
// fmt.Println(wa0gi)
|
||||||
|
},
|
||||||
|
100000,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
}, {
|
||||||
|
"fail",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(9e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {},
|
||||||
|
100000,
|
||||||
|
true,
|
||||||
|
"insufficient mint supply",
|
||||||
|
true,
|
||||||
|
}, {
|
||||||
|
"invalid sender",
|
||||||
|
func() []byte {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
method,
|
||||||
|
s.signerTwo,
|
||||||
|
big.NewInt(9e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
return input
|
||||||
|
},
|
||||||
|
func() {},
|
||||||
|
100000,
|
||||||
|
true,
|
||||||
|
"sender is not WA0GI",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(tc.name, func() {
|
||||||
|
s.SetupTest()
|
||||||
|
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(8e18),
|
||||||
|
big.NewInt(4e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
|
||||||
|
if tc.isSenderWA0GI {
|
||||||
|
_, err = s.runTx(tc.malleate(), s.wa0gibase.getWA0GI(), 10000000, uint256.NewInt(0), false)
|
||||||
|
} else {
|
||||||
|
_, err = s.runTx(tc.malleate(), s.signerTwo, 10000000, uint256.NewInt(0), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expErr {
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Contains(err.Error(), tc.errContains)
|
||||||
|
} else {
|
||||||
|
s.Require().NoError(err)
|
||||||
|
tc.postCheck()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestSetMinterCap() {
|
||||||
|
agency := s.wa0gibase.getAgency()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
caps []struct {
|
||||||
|
account common.Address
|
||||||
|
cap *big.Int
|
||||||
|
initialSupply *big.Int
|
||||||
|
}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
caps: []struct {
|
||||||
|
account common.Address
|
||||||
|
cap *big.Int
|
||||||
|
initialSupply *big.Int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000000"),
|
||||||
|
cap: big.NewInt(100000),
|
||||||
|
initialSupply: big.NewInt(50000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000001"),
|
||||||
|
cap: big.NewInt(200000),
|
||||||
|
initialSupply: big.NewInt(100000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000002"),
|
||||||
|
cap: big.NewInt(300000),
|
||||||
|
initialSupply: big.NewInt(150000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000003"),
|
||||||
|
cap: big.NewInt(400000),
|
||||||
|
initialSupply: big.NewInt(200000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000002"),
|
||||||
|
cap: big.NewInt(500000),
|
||||||
|
initialSupply: big.NewInt(250000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000001"),
|
||||||
|
cap: big.NewInt(600000),
|
||||||
|
initialSupply: big.NewInt(300000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
account: common.HexToAddress("0x0000000000000000000000000000000000000000"),
|
||||||
|
cap: big.NewInt(700000),
|
||||||
|
initialSupply: big.NewInt(350000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s.Run("invalid authority", func() {
|
||||||
|
s.SetupTest()
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
s.signerOne,
|
||||||
|
big.NewInt(8e18),
|
||||||
|
big.NewInt(4e18),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, s.signerOne, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Require().Error(err)
|
||||||
|
s.Require().Contains(err.Error(), "sender is not agency")
|
||||||
|
})
|
||||||
|
for _, tc := range testCases {
|
||||||
|
s.Run(tc.name, func() {
|
||||||
|
s.SetupTest()
|
||||||
|
|
||||||
|
c := make(map[common.Address]struct {
|
||||||
|
Cap *big.Int
|
||||||
|
InitialSupply *big.Int
|
||||||
|
})
|
||||||
|
for _, cap := range tc.caps {
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
cap.account,
|
||||||
|
cap.cap,
|
||||||
|
cap.initialSupply,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
supply, err := s.wa0gibase.getMinterSupply(s.evm, cap.account)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Equal(supply.Cap, cap.cap)
|
||||||
|
s.Require().Equal(supply.InitialSupply, cap.initialSupply)
|
||||||
|
s.Require().Equal(supply.Supply, cap.initialSupply)
|
||||||
|
c[cap.account] = struct {
|
||||||
|
Cap *big.Int
|
||||||
|
InitialSupply *big.Int
|
||||||
|
}{
|
||||||
|
Cap: cap.cap,
|
||||||
|
InitialSupply: cap.initialSupply,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for account, cap := range c {
|
||||||
|
supply, err := s.wa0gibase.getMinterSupply(s.evm, account)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Equal(supply.Cap, cap.Cap)
|
||||||
|
s.Require().Equal(supply.InitialSupply, cap.InitialSupply)
|
||||||
|
s.Require().Equal(supply.Supply, cap.InitialSupply)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MintBurn struct {
|
||||||
|
IsMint bool
|
||||||
|
Minter common.Address
|
||||||
|
Amount *big.Int
|
||||||
|
Success bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *WrappedA0giBaseTestSuite) TestSetMintBurn() {
|
||||||
|
agency := s.wa0gibase.getAgency()
|
||||||
|
|
||||||
|
minter1 := common.HexToAddress("0x0000000000000000000000000000000000000001")
|
||||||
|
minter2 := common.HexToAddress("0x0000000000000000000000000000000000000002")
|
||||||
|
|
||||||
|
// set mint cap of minter 1 to 8 a0gi
|
||||||
|
input, err := s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
minter1,
|
||||||
|
big.NewInt(8e18),
|
||||||
|
big.NewInt(0),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
// set mint cap of minter 2 to 5 a0gi
|
||||||
|
input, err = s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionSetMinterCap,
|
||||||
|
minter2,
|
||||||
|
big.NewInt(5e18),
|
||||||
|
big.NewInt(0),
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, agency, 10000000, uint256.NewInt(0), false)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
testCases := []MintBurn{
|
||||||
|
// #0, failed burn
|
||||||
|
{
|
||||||
|
IsMint: false,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(1e18),
|
||||||
|
Success: false,
|
||||||
|
},
|
||||||
|
// #1, mint 5 a0gi by minter 1
|
||||||
|
{
|
||||||
|
IsMint: true,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(5e18),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
// #2, burn 0.5 a0gi by minter 1
|
||||||
|
{
|
||||||
|
IsMint: false,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(5e17),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
// #3, mint 0.7 a0gi by minter 2
|
||||||
|
{
|
||||||
|
IsMint: true,
|
||||||
|
Minter: minter2,
|
||||||
|
Amount: big.NewInt(7e17),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
// #4, mint 2 a0gi by minter 2
|
||||||
|
{
|
||||||
|
IsMint: true,
|
||||||
|
Minter: minter2,
|
||||||
|
Amount: big.NewInt(2e18),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
// #5, burn 0.3 a0gi by minter 2
|
||||||
|
{
|
||||||
|
IsMint: false,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(3e17),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
// #6, failed to mint 4 a0gi by minter 1
|
||||||
|
{
|
||||||
|
IsMint: true,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(4e18),
|
||||||
|
Success: false,
|
||||||
|
},
|
||||||
|
// #7, mint 3.5 a0gi by minter 1
|
||||||
|
{
|
||||||
|
IsMint: true,
|
||||||
|
Minter: minter1,
|
||||||
|
Amount: big.NewInt(3e18 + 5e17),
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
minted := big.NewInt(0)
|
||||||
|
supplied := make(map[common.Address]*big.Int)
|
||||||
|
for _, c := range testCases {
|
||||||
|
if c.IsMint {
|
||||||
|
input, err = s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionMint,
|
||||||
|
c.Minter,
|
||||||
|
c.Amount,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, s.wa0gibase.getWA0GI(), 10000000, uint256.NewInt(0), false)
|
||||||
|
} else {
|
||||||
|
input, err = s.abi.Pack(
|
||||||
|
WrappedA0GIBaseFunctionBurn,
|
||||||
|
c.Minter,
|
||||||
|
c.Amount,
|
||||||
|
)
|
||||||
|
s.Assert().NoError(err)
|
||||||
|
_, err = s.runTx(input, s.wa0gibase.getWA0GI(), 10000000, uint256.NewInt(0), false)
|
||||||
|
}
|
||||||
|
if c.Success {
|
||||||
|
if c.IsMint {
|
||||||
|
minted.Add(minted, c.Amount)
|
||||||
|
if amt, ok := supplied[c.Minter]; ok {
|
||||||
|
amt.Add(amt, c.Amount)
|
||||||
|
} else {
|
||||||
|
supplied[c.Minter] = new(big.Int).Set(c.Amount)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
minted.Sub(minted, c.Amount)
|
||||||
|
if amt, ok := supplied[c.Minter]; ok {
|
||||||
|
amt.Sub(amt, c.Amount)
|
||||||
|
} else {
|
||||||
|
supplied[c.Minter] = new(big.Int).Set(c.Amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Require().NoError(err)
|
||||||
|
supply, err := s.wa0gibase.getMinterSupply(s.evm, c.Minter)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Equal(supplied[c.Minter].Bytes(), supply.Supply.Bytes())
|
||||||
|
} else {
|
||||||
|
s.Require().Error(err)
|
||||||
|
}
|
||||||
|
balance := s.evm.StateDB.GetBalance(s.wa0gibase.getWA0GI())
|
||||||
|
s.Require().Equal(balance.ToBig().Bytes(), minted.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrappedA0giBaseTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(WrappedA0giBaseTestSuite))
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
|
|
@ -141,6 +141,8 @@ require (
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
golang.org/x/mod v0.22.0 // indirect
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
golang.org/x/net v0.36.0 // indirect
|
golang.org/x/net v0.36.0 // indirect
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -514,6 +514,10 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,15 @@ import (
|
||||||
|
|
||||||
type precompileContract struct{}
|
type precompileContract struct{}
|
||||||
|
|
||||||
|
func (precompileContract) Address() common.Address {
|
||||||
|
return common.BytesToAddress([]byte{0x1})
|
||||||
|
}
|
||||||
|
|
||||||
func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 }
|
func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 }
|
||||||
|
|
||||||
func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil }
|
func (p *precompileContract) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestStateOverrideMovePrecompile(t *testing.T) {
|
func TestStateOverrideMovePrecompile(t *testing.T) {
|
||||||
db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ func fuzz(id byte, data []byte) int {
|
||||||
}
|
}
|
||||||
cpy := make([]byte, len(data))
|
cpy := make([]byte, len(data))
|
||||||
copy(cpy, data)
|
copy(cpy, data)
|
||||||
_, err := precompile.Run(cpy)
|
_, err := precompile.Run(nil, &vm.Contract{Input: cpy}, true)
|
||||||
if !bytes.Equal(cpy, data) {
|
if !bytes.Equal(cpy, data) {
|
||||||
panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy))
|
panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue