11package org .tron .core .capsule .utils ;
22
3- import static org .junit .Assert .assertEquals ;
4-
5- import com .google .protobuf .ByteString ;
3+ import java .util .ArrayList ;
64import java .util .List ;
7- import java .util .Vector ;
8- import java .util .stream .Collectors ;
95import lombok .extern .slf4j .Slf4j ;
10- import org .junit .Ignore ;
6+ import org .junit .Assert ;
117import org .junit .Test ;
128import org .tron .common .utils .ByteArray ;
139import org .tron .common .utils .Sha256Hash ;
14- import org .tron .core .capsule .BlockCapsule ;
15- import org .tron .core .capsule .TransactionCapsule ;
16- import org .tron .protos .Protocol ;
10+ import org .tron .core .capsule .utils .MerkleTree .Leaf ;
1711
1812@ Slf4j
1913public class MerkleTreeTest {
2014
21- private static BlockCapsule blockCapsule0 = new BlockCapsule (1 , ByteString
22- .copyFrom (ByteArray
23- .fromHexString ("9938a342238077182498b464ac0292229938a342238077182498b464ac029222" )), 1234 ,
24- ByteString .copyFrom ("1234567" .getBytes ()));
25-
26- private static BlockCapsule blockCapsule1 = new BlockCapsule (1 , ByteString
27- .copyFrom (ByteArray
28- .fromHexString ("9938a342238077182498b464ac0292229938a342238077182498b464ac029222" )), 1234 ,
29- ByteString .copyFrom ("1234567" .getBytes ()));
30-
31- /* private TransactionCapsule transactionCapsule1 = new TransactionCapsule(
32- ByteArray.fromHexString(
33- Wallet.getAddressPreFixString() + "A389132D6639FBDA4FBC8B659264E6B7C90DB086"), 1L);
34- private TransactionCapsule transactionCapsule2 = new TransactionCapsule(
35- ByteArray.fromHexString(
36- Wallet.getAddressPreFixString() + "ED738B3A0FE390EAA71B768B6D02CDBD18FB207B"), 2L);
37- private TransactionCapsule transactionCapsule3 = new TransactionCapsule(
38- ByteArray.fromHexString(
39- Wallet.getAddressPreFixString() + "F25675B364B0E45E2668C1CDD59370136AD8EC2F"), 2L);
40- */
41-
42- public MerkleTreeTest () throws Exception {
43- }
44-
45- @ Ignore
46- @ Test
47- public void testMerkleTreeTest () {
48- Sha256Hash hash1 = getBeforeZeroHash ();
49- MerkleTree tree = MerkleTree .getInstance ().createTree (getZeroIds ());
50-
51- logger .info ("Transaction[X] Compare :" );
52- logger .info ("left: {}" , hash1 );
53- logger .info ("right: {}" , tree .getRoot ().getHash ());
54-
55- assertEquals (hash1 , tree .getRoot ().getHash ());
56-
57- Sha256Hash hash2 = getBeforeTxHash ();
58- tree .createTree (getTxIds2 (blockCapsule1 ));
59-
60- logger .info ("Transaction[O] Compare :" );
61- logger .info ("left: {}" , hash2 );
62- logger .info ("right: {}" , tree .getRoot ().getHash ());
63-
64- assertEquals (hash2 , tree .getRoot ().getHash ());
65- }
66-
67- private Sha256Hash getBeforeHash (Vector <Sha256Hash > ids ) {
68- int hashNum = ids .size ();
69-
70- while (hashNum > 1 ) {
71- int max = hashNum - (hashNum & 1 );
72- int k = 0 ;
73- for (int i = 0 ; i < max ; i += 2 ) {
74- ids .set (k ++, Sha256Hash .of ((ids .get (i ).getByteString ()
75- .concat (ids .get (i + 1 ).getByteString ()))
76- .toByteArray ()));
77- }
78-
79- if (hashNum % 2 == 1 ) {
80- ids .set (k ++, ids .get (max ));
81- }
82- hashNum = k ;
15+ private static List <Sha256Hash > getHash (int hashNum ) {
16+ List <Sha256Hash > hashList = new ArrayList <Sha256Hash >();
17+ for (int i = 0 ; i < hashNum ; i ++) {
18+ byte [] bytes = new byte [4 ];
19+ bytes [3 ] = (byte ) (i & 0xFF );
20+ bytes [2 ] = (byte ) ((i >> 8 ) & 0xFF );
21+ bytes [1 ] = (byte ) ((i >> 16 ) & 0xFF );
22+ bytes [0 ] = (byte ) ((i >> 24 ) & 0xFF );
23+ hashList .add (Sha256Hash .of (bytes ));
8324 }
84-
85- return ids .firstElement ();
25+ return hashList ;
8626 }
8727
88- private Sha256Hash getBeforeZeroHash ( ) {
89- return getBeforeHash ( getZeroIds ());
28+ private static Sha256Hash computeHash ( Sha256Hash leftHash , Sha256Hash rightHash ) {
29+ return Sha256Hash . of ( leftHash . getByteString (). concat ( rightHash . getByteString ()). toByteArray ());
9030 }
9131
92- private Sha256Hash getBeforeTxHash () {
93- return getBeforeHash (getTxIds1 (blockCapsule0 ));
32+ @ Test
33+ /**
34+ * Make a merkletree with no hash.
35+ * Will throw a exception.
36+ */
37+ public void test0HashNum () {
38+ List <Sha256Hash > hashList = getHash (0 ); //Empty list.
39+ try {
40+ MerkleTree .getInstance ().createTree (hashList );
41+ Assert .assertFalse (true );
42+ } catch (Exception e ) {
43+ Assert .assertTrue (e instanceof IndexOutOfBoundsException );
44+ }
9445 }
9546
96- private Vector <Sha256Hash > getZeroIds () {
97- Vector <Sha256Hash > ids = new Vector <>();
98- ids .add (Sha256Hash .ZERO_HASH );
99- return ids ;
47+ @ Test
48+ /**
49+ * Make a merkletree with 1 hash.
50+ * root
51+ * / \
52+ * H1 null
53+ * / \
54+ * null null
55+ */
56+ public void test1HashNum () {
57+ List <Sha256Hash > hashList = getHash (1 );
58+ MerkleTree tree = MerkleTree .getInstance ().createTree (hashList );
59+ Leaf root = tree .getRoot ();
60+ Assert .assertEquals (root .getHash (), hashList .get (0 ));
61+
62+ Leaf left = root .getLeft ();
63+ Assert .assertEquals (left .getHash (), hashList .get (0 ));
64+ Assert .assertTrue (left .getLeft () == null );
65+ Assert .assertTrue (left .getRight () == null );
66+
67+ Assert .assertTrue (root .getRight () == null );
10068 }
10169
102- private Vector <Sha256Hash > getTxIds1 (BlockCapsule blockCapsule ) {
103- return getSha256Hashes (blockCapsule );
70+ @ Test
71+ /**
72+ * Make a merkletree with 2 hash.
73+ * root
74+ * / \
75+ * H1 H2
76+ * / \ / \
77+ *null null null null
78+ */
79+ public void test2HashNum () {
80+ List <Sha256Hash > hashList = getHash (2 );
81+ MerkleTree tree = MerkleTree .getInstance ().createTree (hashList );
82+ Leaf root = tree .getRoot ();
83+ Assert .assertEquals (root .getHash (), computeHash (hashList .get (0 ), hashList .get (1 )));
84+
85+ Leaf left = root .getLeft ();
86+ Assert .assertEquals (left .getHash (), hashList .get (0 ));
87+ Assert .assertTrue (left .getLeft () == null );
88+ Assert .assertTrue (left .getRight () == null );
89+
90+ Leaf right = root .getRight ();
91+ Assert .assertEquals (right .getHash (), hashList .get (1 ));
92+ Assert .assertTrue (right .getLeft () == null );
93+ Assert .assertTrue (right .getRight () == null );
10494 }
10595
106- private Vector <Sha256Hash > getTxIds2 (BlockCapsule blockCapsule ) {
107- return getSha256Hashes (blockCapsule );
96+ @ Test
97+ /**
98+ * Make a merkletree with any num hash.
99+ *
100+ *rank0 root
101+ *rank1 0 1
102+ *rank2 0 1 2
103+ *rank3 0 1 2 3 4
104+ *rank4 0 1 2 3 4 5 6 7 8 9
105+ *rank5 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
106+ *
107+ * leftNum = 2 * headNum
108+ * rightNum = leftNum + 1
109+ * curBank < maxRank, there must have left child
110+ * if have left child but no right child, headHash = leftHash
111+ * if both have left child and right child, headHash = SHA256(leftHash||rightHash)
112+ * curBank = maxRank, no child, it is real leaf. Its hash in hashList.
113+ */
114+ public void testAnyHashNum () {
115+ int maxNum = 128 ;
116+ for (int hashNum = 1 ; hashNum <= maxNum ; hashNum ++){
117+ int maxRank = getRank (hashNum );
118+ List <Sha256Hash > hashList = getHash (hashNum );
119+ MerkleTree tree = MerkleTree .getInstance ().createTree (hashList );
120+ Leaf root = tree .getRoot ();
121+ pareTree (root , hashList , maxRank , 0 , 0 );
122+ }
108123 }
109124
110- private Vector <Sha256Hash > getSha256Hashes (BlockCapsule blockCapsule ) {
111- /* blockCapsule.addTransaction(transactionCapsule1);
112- blockCapsule.addTransaction(transactionCapsule2);
113- blockCapsule.addTransaction(transactionCapsule3);
114-
115- List<Protocol.Transaction> transactionList = blockCapsule.getInstance().getTransactionsList();
116- return getSha256Hashes(transactionList); */
117- return null ;
125+ //number: the number of hash
126+ private static void pareTree (Leaf head , List <Sha256Hash > hashList , int maxRank , int curBank ,
127+ int number ) {
128+ Leaf left = head .getLeft ();
129+ Leaf right = head .getRight ();
130+ if (curBank < maxRank ) {
131+ curBank ++;
132+ number = number << 1 ;
133+ pareTree (left , hashList , maxRank , curBank , number );
134+ number ++;
135+ if ( (number <<(maxRank -curBank )) >= hashList .size ()) { //The smallest leaf child number = number<<(maxRank-curBank)
136+ Assert .assertTrue (right == null );
137+ Assert .assertEquals (head .getHash (), left .getHash ()); //No right, leaf = left
138+ } else {
139+ pareTree (right , hashList , maxRank , curBank , number );
140+ Assert .assertEquals (head .getHash (), computeHash (left .getHash (), right .getHash ())); //hash = sha256(left || right)
141+ }
142+ } else {
143+ // last rank, no child, it is real leaf. Its hash in hashList.
144+ Assert .assertTrue (left == null );
145+ Assert .assertTrue (right == null );
146+ Assert .assertEquals (head .getHash (), hashList .get (number ));
147+ System .out .println ("curBank :" + curBank + " number :" + number );
148+ System .out .println (ByteArray .toHexString (head .getHash ().getBytes ()));
149+ }
118150 }
119151
120- private Vector <Sha256Hash > getSha256Hashes (List <Protocol .Transaction > transactionList ) {
121- return transactionList .stream ()
122- .map (TransactionCapsule ::new )
123- .map (TransactionCapsule ::getHash )
124- .collect (Collectors .toCollection (Vector ::new ));
152+ private static int getRank (int num ) {
153+ if (num <= 0 ) {
154+ return 0 ;
155+ }
156+ if (num == 1 ) {
157+ return 1 ;
158+ }
159+ int rank = 0 ;
160+ int temp = num ;
161+ while (num > 0 ) {
162+ num = num >> 1 ;
163+ rank ++;
164+ }
165+ if (temp == Math .pow (2 , rank - 1 )) {
166+ rank -= 1 ;
167+ }
168+ return rank ;
125169 }
126170}
0 commit comments