The first line aggregates the text block, line by line, and also tries to find a number to use as a sorting critea afterwards. The if-clause if($0+0==$0) evaluates true when it finds a number.
The second block executes when it finds an "END" in the input, so it saves the block in an associative array, indexing it using the number found in the block.
awk '{block=block"\n"$0; if($0+0==$0) num=$0;}
/^END$/ {blks[num]=block; block=""}
END {for(key in blks) print blks[key]}' file
The last line is just printing every entry of the array when it reaches the end of the input file.
Note that the associative array is already sorted (that is how it works internally), so we just need to iterate over it printing every entry.
For instance, look at the following awk script:
echo | awk '{a[2]="b"; a[1]="a"; a[3]="c"; for(key in a) print a[key];}'
It outputs:
a
b
c
In my answer I'm printing an extra \n before each block, I suppose this is not a problem. The output for your example is:
BEGIN
hello4
2
world5
END
BEGIN
hello6
4
END
BEGIN
hello2
5
world1
END
If you don't want the extra line, replace the first block of my awk script with:
{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}}
Here is the one-liner version:
awk '{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}} /^END$/ {blks[num]=block; block=""} END {for(key in blks) print blks[key]}' file