github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/internal/testchain/address.go (about)

     1  package testchain
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/core/block"
     8  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
     9  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    10  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    11  	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
    12  	"github.com/nspcc-dev/neo-go/pkg/io"
    13  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    14  	"github.com/nspcc-dev/neo-go/pkg/util"
    15  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  // privNetKeys is a list of unencrypted WIFs sorted by public key.
    20  var privNetKeys = []string{
    21  	"KzfPUYDC9n2yf4fK5ro4C8KMcdeXtFuEnStycbZgX3GomiUsvX6W",
    22  	"KzgWE3u3EDp13XPXXuTKZxeJ3Gi8Bsm8f9ijY3ZsCKKRvZUo1Cdn",
    23  	"KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY",
    24  	"L2oEXKRAAMiPEZukwR5ho2S6SMeQLhcK9mF71ZnF7GvT8dU4Kkgz",
    25  
    26  	// Provide 2 committee extra members so that the committee address differs from
    27  	// the validators one.
    28  	"L1Tr1iq5oz1jaFaMXP21sHDkJYDDkuLtpvQ4wRf1cjKvJYvnvpAb",
    29  	"Kz6XTUrExy78q8f4MjDHnwz8fYYyUE8iPXwPRAkHa3qN2JcHYm7e",
    30  }
    31  
    32  // ValidatorsCount returns the number of validators in the testchain.
    33  const ValidatorsCount = 4
    34  
    35  var (
    36  	// ids maps validators order by public key sorting to validators ID.
    37  	// That is the order of the validator in the StandByValidators list.
    38  	ids = []int{1, 3, 0, 2, 4, 5}
    39  	// orders maps validators id to its order by public key sorting.
    40  	orders = []int{2, 0, 3, 1, 4, 5}
    41  )
    42  
    43  // Size returns testchain initial validators amount.
    44  func Size() int {
    45  	return ValidatorsCount
    46  }
    47  
    48  // CommitteeSize returns testchain committee size.
    49  func CommitteeSize() int {
    50  	return len(privNetKeys)
    51  }
    52  
    53  // IDToOrder returns node's order in privnet.
    54  func IDToOrder(id int) int {
    55  	return orders[id]
    56  }
    57  
    58  // WIF returns the unencrypted wif of the specified validator.
    59  func WIF(i int) string {
    60  	return privNetKeys[i]
    61  }
    62  
    63  // PrivateKey returns the private key of node #i.
    64  func PrivateKey(i int) *keys.PrivateKey {
    65  	wif := WIF(i)
    66  	priv, err := keys.NewPrivateKeyFromWIF(wif)
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  	return priv
    71  }
    72  
    73  // PrivateKeyByID returns private keys of a node with the specified id.
    74  func PrivateKeyByID(id int) *keys.PrivateKey {
    75  	return PrivateKey(IDToOrder(id))
    76  }
    77  
    78  // MultisigVerificationScript returns script hash of the consensus multisig address.
    79  func MultisigVerificationScript() []byte {
    80  	var pubs keys.PublicKeys
    81  	for i := range privNetKeys[:ValidatorsCount] {
    82  		priv := PrivateKey(ids[i])
    83  		pubs = append(pubs, priv.PublicKey())
    84  	}
    85  
    86  	script, err := smartcontract.CreateDefaultMultiSigRedeemScript(pubs)
    87  	if err != nil {
    88  		panic(err)
    89  	}
    90  	return script
    91  }
    92  
    93  // MultisigScriptHash returns consensus address as Uint160.
    94  func MultisigScriptHash() util.Uint160 {
    95  	return hash.Hash160(MultisigVerificationScript())
    96  }
    97  
    98  // MultisigAddress return consensus address as string.
    99  func MultisigAddress() string {
   100  	return address.Uint160ToString(MultisigScriptHash())
   101  }
   102  
   103  // CommitteeVerificationScript returns script hash of the committee multisig address.
   104  func CommitteeVerificationScript() []byte {
   105  	var pubs keys.PublicKeys
   106  	for i := range privNetKeys {
   107  		priv := PrivateKey(ids[i])
   108  		pubs = append(pubs, priv.PublicKey())
   109  	}
   110  
   111  	script, err := smartcontract.CreateMajorityMultiSigRedeemScript(pubs)
   112  	if err != nil {
   113  		panic(err)
   114  	}
   115  	return script
   116  }
   117  
   118  // CommitteeScriptHash returns committee address as Uint160.
   119  func CommitteeScriptHash() util.Uint160 {
   120  	return hash.Hash160(CommitteeVerificationScript())
   121  }
   122  
   123  // CommitteeAddress return committee address as string.
   124  func CommitteeAddress() string {
   125  	return address.Uint160ToString(CommitteeScriptHash())
   126  }
   127  
   128  // Sign signs data by all consensus nodes and returns invocation script.
   129  func Sign(h hash.Hashable) []byte {
   130  	buf := io.NewBufBinWriter()
   131  	for i := 0; i < 3; i++ {
   132  		pKey := PrivateKey(i)
   133  		sig := pKey.SignHashable(uint32(Network()), h)
   134  		if len(sig) != 64 {
   135  			panic("wrong signature length")
   136  		}
   137  		emit.Bytes(buf.BinWriter, sig)
   138  	}
   139  	return buf.Bytes()
   140  }
   141  
   142  // SignCommittee signs data by a majority of committee members.
   143  func SignCommittee(h hash.Hashable) []byte {
   144  	buf := io.NewBufBinWriter()
   145  	for i := 0; i < CommitteeSize()/2+1; i++ {
   146  		pKey := PrivateKey(i)
   147  		sig := pKey.SignHashable(uint32(Network()), h)
   148  		if len(sig) != 64 {
   149  			panic("wrong signature length")
   150  		}
   151  		emit.Bytes(buf.BinWriter, sig)
   152  	}
   153  	return buf.Bytes()
   154  }
   155  
   156  // NewBlock creates a new block for the given blockchain with the given offset
   157  // (usually, 1), primary node index and transactions.
   158  func NewBlock(t *testing.T, bc Ledger, offset uint32, primary uint32, txs ...*transaction.Transaction) *block.Block {
   159  	witness := transaction.Witness{VerificationScript: MultisigVerificationScript()}
   160  	height := bc.BlockHeight()
   161  	h := bc.GetHeaderHash(height)
   162  	hdr, err := bc.GetHeader(h)
   163  	require.NoError(t, err)
   164  	b := &block.Block{
   165  		Header: block.Header{
   166  			PrevHash:      hdr.Hash(),
   167  			Timestamp:     (uint64(time.Now().UTC().Unix()) + uint64(hdr.Index)) * 1000,
   168  			Index:         hdr.Index + offset,
   169  			PrimaryIndex:  byte(primary),
   170  			NextConsensus: witness.ScriptHash(),
   171  			Script:        witness,
   172  		},
   173  		Transactions: txs,
   174  	}
   175  	b.RebuildMerkleRoot()
   176  
   177  	b.Script.InvocationScript = Sign(b)
   178  	return b
   179  }